Fossil SCM

Switch to the msteveb linenoise fork and update to the trunk sqlite3 shell.c to account for that change, per /chat discussion.

stephan 2024-05-30 11:17 trunk
Commit d6f8f324eff817e4e78bdf20f9dc136a60bd6c3d1f9306139b13862ff93ffa54
3 files changed +2590 -1030 +97 -23 +116 -8
+2590 -1030
--- extsrc/linenoise.c
+++ extsrc/linenoise.c
@@ -1,19 +1,718 @@
1
+#line 1 "utf8.h"
2
+#ifndef UTF8_UTIL_H
3
+#define UTF8_UTIL_H
4
+
5
+#ifdef __cplusplus
6
+extern "C" {
7
+#endif
8
+
9
+/**
10
+ * UTF-8 utility functions
11
+ *
12
+ * (c) 2010-2019 Steve Bennett <[email protected]>
13
+ *
14
+ * See utf8.c for licence details.
15
+ */
16
+
17
+#ifndef USE_UTF8
18
+#include <ctype.h>
19
+
20
+#define MAX_UTF8_LEN 1
21
+
22
+/* No utf-8 support. 1 byte = 1 char */
23
+#define utf8_strlen(S, B) ((B) < 0 ? (int)strlen(S) : (B))
24
+#define utf8_strwidth(S, B) utf8_strlen((S), (B))
25
+#define utf8_tounicode(S, CP) (*(CP) = (unsigned char)*(S), 1)
26
+#define utf8_index(C, I) (I)
27
+#define utf8_charlen(C) 1
28
+ #define utf8_width(C) 1
29
+
30
+#else
31
+
32
+#define MAX_UTF8_LEN 4
33
+
34
+/**
35
+ * Converts the given unicode codepoint (0 - 0x1fffff) to utf-8
36
+ * and stores the result at 'p'.
37
+ *
38
+ * Returns the number of utf-8 characters
39
+ */
40
+int utf8_fromunicode(char *p, unsigned uc);
41
+
42
+/**
43
+ * Returns the length of the utf-8 sequence starting with 'c'.
44
+ *
45
+ * Returns 1-4, or -1 if this is not a valid start byte.
46
+ *
47
+ * Note that charlen=4 is not supported by the rest of the API.
48
+ */
49
+int utf8_charlen(int c);
50
+
51
+/**
52
+ * Returns the number of characters in the utf-8
53
+ * string of the given byte length.
54
+ *
55
+ * Any bytes which are not part of an valid utf-8
56
+ * sequence are treated as individual characters.
57
+ *
58
+ * The string *must* be null terminated.
59
+ *
60
+ * Does not support unicode code points > \u1fffff
61
+ */
62
+int utf8_strlen(const char *str, int bytelen);
63
+
64
+/**
65
+ * Calculates the display width of the first 'charlen' characters in 'str'.
66
+ * See utf8_width()
67
+ */
68
+int utf8_strwidth(const char *str, int charlen);
69
+
70
+/**
71
+ * Returns the byte index of the given character in the utf-8 string.
72
+ *
73
+ * The string *must* be null terminated.
74
+ *
75
+ * This will return the byte length of a utf-8 string
76
+ * if given the char length.
77
+ */
78
+int utf8_index(const char *str, int charindex);
79
+
80
+/**
81
+ * Returns the unicode codepoint corresponding to the
82
+ * utf-8 sequence 'str'.
83
+ *
84
+ * Stores the result in *uc and returns the number of bytes
85
+ * consumed.
86
+ *
87
+ * If 'str' is null terminated, then an invalid utf-8 sequence
88
+ * at the end of the string will be returned as individual bytes.
89
+ *
90
+ * If it is not null terminated, the length *must* be checked first.
91
+ *
92
+ * Does not support unicode code points > \u1fffff
93
+ */
94
+int utf8_tounicode(const char *str, int *uc);
95
+
96
+/**
97
+ * Returns the width (in characters) of the given unicode codepoint.
98
+ * This is 1 for normal letters and 0 for combining characters and 2 for wide characters.
99
+ */
100
+int utf8_width(int ch);
101
+
102
+#endif
103
+
104
+#ifdef __cplusplus
105
+}
106
+#endif
107
+
108
+#endif
109
+#line 1 "utf8.c"
110
+/**
111
+ * UTF-8 utility functions
112
+ *
113
+ * (c) 2010-2019 Steve Bennett <[email protected]>
114
+ *
115
+ * All rights reserved.
116
+ *
117
+ * Redistribution and use in source and binary forms, with or without
118
+ * modification, are permitted provided that the following conditions are met:
119
+ *
120
+ * * Redistributions of source code must retain the above copyright notice,
121
+ * this list of conditions and the following disclaimer.
122
+ *
123
+ * * Redistributions in binary form must reproduce the above copyright notice,
124
+ * this list of conditions and the following disclaimer in the documentation
125
+ * and/or other materials provided with the distribution.
126
+ *
127
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
128
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
129
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
130
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
131
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
132
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
133
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
134
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
135
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
136
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
137
+ */
138
+
139
+#include <ctype.h>
140
+#include <stdlib.h>
141
+#include <string.h>
142
+#include <stdio.h>
143
+#ifndef UTF8_UTIL_H
144
+#include "utf8.h"
145
+#endif
146
+
147
+#ifdef USE_UTF8
148
+int utf8_fromunicode(char *p, unsigned uc)
149
+{
150
+ if (uc <= 0x7f) {
151
+ *p = uc;
152
+ return 1;
153
+ }
154
+ else if (uc <= 0x7ff) {
155
+ *p++ = 0xc0 | ((uc & 0x7c0) >> 6);
156
+ *p = 0x80 | (uc & 0x3f);
157
+ return 2;
158
+ }
159
+ else if (uc <= 0xffff) {
160
+ *p++ = 0xe0 | ((uc & 0xf000) >> 12);
161
+ *p++ = 0x80 | ((uc & 0xfc0) >> 6);
162
+ *p = 0x80 | (uc & 0x3f);
163
+ return 3;
164
+ }
165
+ /* Note: We silently truncate to 21 bits here: 0x1fffff */
166
+ else {
167
+ *p++ = 0xf0 | ((uc & 0x1c0000) >> 18);
168
+ *p++ = 0x80 | ((uc & 0x3f000) >> 12);
169
+ *p++ = 0x80 | ((uc & 0xfc0) >> 6);
170
+ *p = 0x80 | (uc & 0x3f);
171
+ return 4;
172
+ }
173
+}
174
+
175
+int utf8_charlen(int c)
176
+{
177
+ if ((c & 0x80) == 0) {
178
+ return 1;
179
+ }
180
+ if ((c & 0xe0) == 0xc0) {
181
+ return 2;
182
+ }
183
+ if ((c & 0xf0) == 0xe0) {
184
+ return 3;
185
+ }
186
+ if ((c & 0xf8) == 0xf0) {
187
+ return 4;
188
+ }
189
+ /* Invalid sequence */
190
+ return -1;
191
+}
192
+
193
+int utf8_strlen(const char *str, int bytelen)
194
+{
195
+ int charlen = 0;
196
+ if (bytelen < 0) {
197
+ bytelen = strlen(str);
198
+ }
199
+ while (bytelen > 0) {
200
+ int c;
201
+ int l = utf8_tounicode(str, &c);
202
+ charlen++;
203
+ str += l;
204
+ bytelen -= l;
205
+ }
206
+ return charlen;
207
+}
208
+
209
+int utf8_strwidth(const char *str, int charlen)
210
+{
211
+ int width = 0;
212
+ while (charlen) {
213
+ int c;
214
+ int l = utf8_tounicode(str, &c);
215
+ width += utf8_width(c);
216
+ str += l;
217
+ charlen--;
218
+ }
219
+ return width;
220
+}
221
+
222
+int utf8_index(const char *str, int index)
223
+{
224
+ const char *s = str;
225
+ while (index--) {
226
+ int c;
227
+ s += utf8_tounicode(s, &c);
228
+ }
229
+ return s - str;
230
+}
231
+
232
+int utf8_tounicode(const char *str, int *uc)
233
+{
234
+ unsigned const char *s = (unsigned const char *)str;
235
+
236
+ if (s[0] < 0xc0) {
237
+ *uc = s[0];
238
+ return 1;
239
+ }
240
+ if (s[0] < 0xe0) {
241
+ if ((s[1] & 0xc0) == 0x80) {
242
+ *uc = ((s[0] & ~0xc0) << 6) | (s[1] & ~0x80);
243
+ if (*uc >= 0x80) {
244
+ return 2;
245
+ }
246
+ /* Otherwise this is an invalid sequence */
247
+ }
248
+ }
249
+ else if (s[0] < 0xf0) {
250
+ if (((str[1] & 0xc0) == 0x80) && ((str[2] & 0xc0) == 0x80)) {
251
+ *uc = ((s[0] & ~0xe0) << 12) | ((s[1] & ~0x80) << 6) | (s[2] & ~0x80);
252
+ if (*uc >= 0x800) {
253
+ return 3;
254
+ }
255
+ /* Otherwise this is an invalid sequence */
256
+ }
257
+ }
258
+ else if (s[0] < 0xf8) {
259
+ if (((str[1] & 0xc0) == 0x80) && ((str[2] & 0xc0) == 0x80) && ((str[3] & 0xc0) == 0x80)) {
260
+ *uc = ((s[0] & ~0xf0) << 18) | ((s[1] & ~0x80) << 12) | ((s[2] & ~0x80) << 6) | (s[3] & ~0x80);
261
+ if (*uc >= 0x10000) {
262
+ return 4;
263
+ }
264
+ /* Otherwise this is an invalid sequence */
265
+ }
266
+ }
267
+
268
+ /* Invalid sequence, so just return the byte */
269
+ *uc = *s;
270
+ return 1;
271
+}
272
+
273
+struct utf8range {
274
+ int lower; /* lower inclusive */
275
+ int upper; /* upper exclusive */
276
+};
277
+
278
+/* From http://unicode.org/Public/UNIDATA/UnicodeData.txt */
279
+static const struct utf8range unicode_range_combining[] = {
280
+ { 0x0300, 0x0370 }, { 0x0483, 0x048a }, { 0x0591, 0x05d0 }, { 0x0610, 0x061b },
281
+ { 0x064b, 0x0660 }, { 0x0670, 0x0671 }, { 0x06d6, 0x06dd }, { 0x06df, 0x06e5 },
282
+ { 0x06e7, 0x06ee }, { 0x0711, 0x0712 }, { 0x0730, 0x074d }, { 0x07a6, 0x07b1 },
283
+ { 0x07eb, 0x07f4 }, { 0x0816, 0x0830 }, { 0x0859, 0x085e }, { 0x08d4, 0x0904 },
284
+ { 0x093a, 0x0958 }, { 0x0962, 0x0964 }, { 0x0981, 0x0985 }, { 0x09bc, 0x09ce },
285
+ { 0x09d7, 0x09dc }, { 0x09e2, 0x09e6 }, { 0x0a01, 0x0a05 }, { 0x0a3c, 0x0a59 },
286
+ { 0x0a70, 0x0a72 }, { 0x0a75, 0x0a85 }, { 0x0abc, 0x0ad0 }, { 0x0ae2, 0x0ae6 },
287
+ { 0x0afa, 0x0b05 }, { 0x0b3c, 0x0b5c }, { 0x0b62, 0x0b66 }, { 0x0b82, 0x0b83 },
288
+ { 0x0bbe, 0x0bd0 }, { 0x0bd7, 0x0be6 }, { 0x0c00, 0x0c05 }, { 0x0c3e, 0x0c58 },
289
+ { 0x0c62, 0x0c66 }, { 0x0c81, 0x0c85 }, { 0x0cbc, 0x0cde }, { 0x0ce2, 0x0ce6 },
290
+ { 0x0d00, 0x0d05 }, { 0x0d3b, 0x0d4e }, { 0x0d57, 0x0d58 }, { 0x0d62, 0x0d66 },
291
+ { 0x0d82, 0x0d85 }, { 0x0dca, 0x0de6 }, { 0x0df2, 0x0df4 }, { 0x0e31, 0x0e32 },
292
+ { 0x0e34, 0x0e3f }, { 0x0e47, 0x0e4f }, { 0x0eb1, 0x0eb2 }, { 0x0eb4, 0x0ebd },
293
+ { 0x0ec8, 0x0ed0 }, { 0x0f18, 0x0f1a }, { 0x0f35, 0x0f3a }, { 0x0f3e, 0x0f40 },
294
+ { 0x0f71, 0x0f88 }, { 0x0f8d, 0x0fbe }, { 0x0fc6, 0x0fc7 }, { 0x102b, 0x103f },
295
+ { 0x1056, 0x105a }, { 0x105e, 0x1065 }, { 0x1067, 0x106e }, { 0x1071, 0x1075 },
296
+ { 0x1082, 0x1090 }, { 0x109a, 0x109e }, { 0x135d, 0x1360 }, { 0x1712, 0x1720 },
297
+ { 0x1732, 0x1735 }, { 0x1752, 0x1760 }, { 0x1772, 0x1780 }, { 0x17b4, 0x17d4 },
298
+ { 0x17dd, 0x17e0 }, { 0x180b, 0x180e }, { 0x1885, 0x1887 }, { 0x18a9, 0x18aa },
299
+ { 0x1920, 0x1940 }, { 0x1a17, 0x1a1e }, { 0x1a55, 0x1a80 }, { 0x1ab0, 0x1b05 },
300
+ { 0x1b34, 0x1b45 }, { 0x1b6b, 0x1b74 }, { 0x1b80, 0x1b83 }, { 0x1ba1, 0x1bae },
301
+ { 0x1be6, 0x1bfc }, { 0x1c24, 0x1c3b }, { 0x1cd0, 0x1ce9 }, { 0x1ced, 0x1cee },
302
+ { 0x1cf2, 0x1cf5 }, { 0x1cf7, 0x1d00 }, { 0x1dc0, 0x1e00 }, { 0x20d0, 0x2100 },
303
+ { 0x2cef, 0x2cf2 }, { 0x2d7f, 0x2d80 }, { 0x2de0, 0x2e00 }, { 0x302a, 0x3030 },
304
+ { 0x3099, 0x309b }, { 0xa66f, 0xa67e }, { 0xa69e, 0xa6a0 }, { 0xa6f0, 0xa6f2 },
305
+ { 0xa802, 0xa803 }, { 0xa806, 0xa807 }, { 0xa80b, 0xa80c }, { 0xa823, 0xa828 },
306
+ { 0xa880, 0xa882 }, { 0xa8b4, 0xa8ce }, { 0xa8e0, 0xa8f2 }, { 0xa926, 0xa92e },
307
+ { 0xa947, 0xa95f }, { 0xa980, 0xa984 }, { 0xa9b3, 0xa9c1 }, { 0xa9e5, 0xa9e6 },
308
+ { 0xaa29, 0xaa40 }, { 0xaa43, 0xaa44 }, { 0xaa4c, 0xaa50 }, { 0xaa7b, 0xaa7e },
309
+ { 0xaab0, 0xaab5 }, { 0xaab7, 0xaab9 }, { 0xaabe, 0xaac2 }, { 0xaaeb, 0xaaf0 },
310
+ { 0xaaf5, 0xab01 }, { 0xabe3, 0xabf0 }, { 0xfb1e, 0xfb1f }, { 0xfe00, 0xfe10 },
311
+ { 0xfe20, 0xfe30 },
312
+};
313
+
314
+/* From http://unicode.org/Public/UNIDATA/EastAsianWidth.txt */
315
+static const struct utf8range unicode_range_wide[] = {
316
+ { 0x1100, 0x115f }, { 0x231a, 0x231b }, { 0x2329, 0x232a }, { 0x23e9, 0x23ec },
317
+ { 0x23f0, 0x23f0 }, { 0x23f3, 0x23f3 }, { 0x25fd, 0x25fe }, { 0x2614, 0x2615 },
318
+ { 0x2648, 0x2653 }, { 0x267f, 0x267f }, { 0x2693, 0x2693 }, { 0x26a1, 0x26a1 },
319
+ { 0x26aa, 0x26ab }, { 0x26bd, 0x26be }, { 0x26c4, 0x26c5 }, { 0x26ce, 0x26ce },
320
+ { 0x26d4, 0x26d4 }, { 0x26ea, 0x26ea }, { 0x26f2, 0x26f3 }, { 0x26f5, 0x26f5 },
321
+ { 0x26fa, 0x26fa }, { 0x26fd, 0x26fd }, { 0x2705, 0x2705 }, { 0x270a, 0x270b },
322
+ { 0x2728, 0x2728 }, { 0x274c, 0x274c }, { 0x274e, 0x274e }, { 0x2753, 0x2755 },
323
+ { 0x2757, 0x2757 }, { 0x2795, 0x2797 }, { 0x27b0, 0x27b0 }, { 0x27bf, 0x27bf },
324
+ { 0x2b1b, 0x2b1c }, { 0x2b50, 0x2b50 }, { 0x2b55, 0x2b55 }, { 0x2e80, 0x2e99 },
325
+ { 0x2e9b, 0x2ef3 }, { 0x2f00, 0x2fd5 }, { 0x2ff0, 0x2ffb }, { 0x3001, 0x303e },
326
+ { 0x3041, 0x3096 }, { 0x3099, 0x30ff }, { 0x3105, 0x312e }, { 0x3131, 0x318e },
327
+ { 0x3190, 0x31ba }, { 0x31c0, 0x31e3 }, { 0x31f0, 0x321e }, { 0x3220, 0x3247 },
328
+ { 0x3250, 0x32fe }, { 0x3300, 0x4dbf }, { 0x4e00, 0xa48c }, { 0xa490, 0xa4c6 },
329
+ { 0xa960, 0xa97c }, { 0xac00, 0xd7a3 }, { 0xf900, 0xfaff }, { 0xfe10, 0xfe19 },
330
+ { 0xfe30, 0xfe52 }, { 0xfe54, 0xfe66 }, { 0xfe68, 0xfe6b }, { 0x16fe0, 0x16fe1 },
331
+ { 0x17000, 0x187ec }, { 0x18800, 0x18af2 }, { 0x1b000, 0x1b11e }, { 0x1b170, 0x1b2fb },
332
+ { 0x1f004, 0x1f004 }, { 0x1f0cf, 0x1f0cf }, { 0x1f18e, 0x1f18e }, { 0x1f191, 0x1f19a },
333
+ { 0x1f200, 0x1f202 }, { 0x1f210, 0x1f23b }, { 0x1f240, 0x1f248 }, { 0x1f250, 0x1f251 },
334
+ { 0x1f260, 0x1f265 }, { 0x1f300, 0x1f320 }, { 0x1f32d, 0x1f335 }, { 0x1f337, 0x1f37c },
335
+ { 0x1f37e, 0x1f393 }, { 0x1f3a0, 0x1f3ca }, { 0x1f3cf, 0x1f3d3 }, { 0x1f3e0, 0x1f3f0 },
336
+ { 0x1f3f4, 0x1f3f4 }, { 0x1f3f8, 0x1f43e }, { 0x1f440, 0x1f440 }, { 0x1f442, 0x1f4fc },
337
+ { 0x1f4ff, 0x1f53d }, { 0x1f54b, 0x1f54e }, { 0x1f550, 0x1f567 }, { 0x1f57a, 0x1f57a },
338
+ { 0x1f595, 0x1f596 }, { 0x1f5a4, 0x1f5a4 }, { 0x1f5fb, 0x1f64f }, { 0x1f680, 0x1f6c5 },
339
+ { 0x1f6cc, 0x1f6cc }, { 0x1f6d0, 0x1f6d2 }, { 0x1f6eb, 0x1f6ec }, { 0x1f6f4, 0x1f6f8 },
340
+ { 0x1f910, 0x1f93e }, { 0x1f940, 0x1f94c }, { 0x1f950, 0x1f96b }, { 0x1f980, 0x1f997 },
341
+ { 0x1f9c0, 0x1f9c0 }, { 0x1f9d0, 0x1f9e6 }, { 0x20000, 0x2fffd }, { 0x30000, 0x3fffd },
342
+};
343
+
344
+#define ARRAYSIZE(A) sizeof(A) / sizeof(*(A))
345
+
346
+static int cmp_range(const void *key, const void *cm)
347
+{
348
+ const struct utf8range *range = (const struct utf8range *)cm;
349
+ int ch = *(int *)key;
350
+ if (ch < range->lower) {
351
+ return -1;
352
+ }
353
+ if (ch >= range->upper) {
354
+ return 1;
355
+ }
356
+ return 0;
357
+}
358
+
359
+static int utf8_in_range(const struct utf8range *range, int num, int ch)
360
+{
361
+ const struct utf8range *r =
362
+ bsearch(&ch, range, num, sizeof(*range), cmp_range);
363
+
364
+ if (r) {
365
+ return 1;
366
+ }
367
+ return 0;
368
+}
369
+
370
+int utf8_width(int ch)
371
+{
372
+ /* short circuit for common case */
373
+ if (isascii(ch)) {
374
+ return 1;
375
+ }
376
+ if (utf8_in_range(unicode_range_combining, ARRAYSIZE(unicode_range_combining), ch)) {
377
+ return 0;
378
+ }
379
+ if (utf8_in_range(unicode_range_wide, ARRAYSIZE(unicode_range_wide), ch)) {
380
+ return 2;
381
+ }
382
+ return 1;
383
+}
384
+#endif
385
+#line 1 "stringbuf.h"
386
+#ifndef STRINGBUF_H
387
+#define STRINGBUF_H
388
+/**
389
+ * resizable string buffer
390
+ *
391
+ * (c) 2017-2020 Steve Bennett <[email protected]>
392
+ *
393
+ * See utf8.c for licence details.
394
+ */
395
+#ifdef __cplusplus
396
+extern "C" {
397
+#endif
398
+
399
+/** @file
400
+ * A stringbuf is a resizing, null terminated string buffer.
401
+ *
402
+ * The buffer is reallocated as necessary.
403
+ *
404
+ * In general it is *not* OK to call these functions with a NULL pointer
405
+ * unless stated otherwise.
406
+ *
407
+ * If USE_UTF8 is defined, supports utf8.
408
+ */
409
+
410
+/**
411
+ * The stringbuf structure should not be accessed directly.
412
+ * Use the functions below.
413
+ */
414
+typedef struct {
415
+ int remaining; /**< Allocated, but unused space */
416
+ int last; /**< Index of the null terminator (and thus the length of the string) */
417
+#ifdef USE_UTF8
418
+ int chars; /**< Count of characters */
419
+#endif
420
+ char *data; /**< Allocated memory containing the string or NULL for empty */
421
+} stringbuf;
422
+
423
+/**
424
+ * Allocates and returns a new stringbuf with no elements.
425
+ */
426
+stringbuf *sb_alloc(void);
427
+
428
+/**
429
+ * Frees a stringbuf.
430
+ * It is OK to call this with NULL.
431
+ */
432
+void sb_free(stringbuf *sb);
433
+
434
+/**
435
+ * Returns an allocated copy of the stringbuf
436
+ */
437
+stringbuf *sb_copy(stringbuf *sb);
438
+
439
+/**
440
+ * Returns the byte length of the buffer.
441
+ *
442
+ * Returns 0 for both a NULL buffer and an empty buffer.
443
+ */
444
+static inline int sb_len(stringbuf *sb) {
445
+ return sb->last;
446
+}
447
+
448
+/**
449
+ * Returns the utf8 character length of the buffer.
450
+ *
451
+ * Returns 0 for both a NULL buffer and an empty buffer.
452
+ */
453
+static inline int sb_chars(stringbuf *sb) {
454
+#ifdef USE_UTF8
455
+ return sb->chars;
456
+#else
457
+ return sb->last;
458
+#endif
459
+}
460
+
461
+/**
462
+ * Appends a null terminated string to the stringbuf
463
+ */
464
+void sb_append(stringbuf *sb, const char *str);
465
+
466
+/**
467
+ * Like sb_append() except does not require a null terminated string.
468
+ * The length of 'str' is given as 'len'
469
+ *
470
+ * Note that in utf8 mode, characters will *not* be counted correctly
471
+ * if a partial utf8 sequence is added with sb_append_len()
472
+ */
473
+void sb_append_len(stringbuf *sb, const char *str, int len);
474
+
475
+/**
476
+ * Returns a pointer to the null terminated string in the buffer.
477
+ *
478
+ * Note this pointer only remains valid until the next modification to the
479
+ * string buffer.
480
+ *
481
+ * The returned pointer can be used to update the buffer in-place
482
+ * as long as care is taken to not overwrite the end of the buffer.
483
+ */
484
+static inline char *sb_str(const stringbuf *sb)
485
+{
486
+ return sb->data;
487
+}
488
+
489
+/**
490
+ * Inserts the given string *before* (zero-based) byte 'index' in the stringbuf.
491
+ * If index is past the end of the buffer, the string is appended,
492
+ * just like sb_append()
493
+ */
494
+void sb_insert(stringbuf *sb, int index, const char *str);
495
+
496
+/**
497
+ * Delete 'len' bytes in the string at the given index.
498
+ *
499
+ * Any bytes past the end of the buffer are ignored.
500
+ * The buffer remains null terminated.
501
+ *
502
+ * If len is -1, deletes to the end of the buffer.
503
+ */
504
+void sb_delete(stringbuf *sb, int index, int len);
505
+
506
+/**
507
+ * Clear to an empty buffer.
508
+ */
509
+void sb_clear(stringbuf *sb);
510
+
511
+/**
512
+ * Return an allocated copy of buffer and frees 'sb'.
513
+ *
514
+ * If 'sb' is empty, returns an allocated copy of "".
515
+ */
516
+char *sb_to_string(stringbuf *sb);
517
+
518
+#ifdef __cplusplus
519
+}
520
+#endif
521
+
522
+#endif
523
+#line 1 "stringbuf.c"
524
+/**
525
+ * resizable string buffer
526
+ *
527
+ * (c) 2017-2020 Steve Bennett <[email protected]>
528
+ *
529
+ * See utf8.c for licence details.
530
+ */
531
+#include <stdlib.h>
532
+#include <string.h>
533
+#include <stdio.h>
534
+#include <ctype.h>
535
+#include <assert.h>
536
+
537
+#ifndef STRINGBUF_H
538
+#include "stringbuf.h"
539
+#endif
540
+#ifdef USE_UTF8
541
+#ifndef UTF8_UTIL_H
542
+#include "utf8.h"
543
+#endif
544
+#endif
545
+
546
+#define SB_INCREMENT 200
547
+
548
+stringbuf *sb_alloc(void)
549
+{
550
+ stringbuf *sb = (stringbuf *)malloc(sizeof(*sb));
551
+ sb->remaining = 0;
552
+ sb->last = 0;
553
+#ifdef USE_UTF8
554
+ sb->chars = 0;
555
+#endif
556
+ sb->data = NULL;
557
+
558
+ return(sb);
559
+}
560
+
561
+void sb_free(stringbuf *sb)
562
+{
563
+ if (sb) {
564
+ free(sb->data);
565
+ }
566
+ free(sb);
567
+}
568
+
569
+static void sb_realloc(stringbuf *sb, int newlen)
570
+{
571
+ sb->data = (char *)realloc(sb->data, newlen);
572
+ sb->remaining = newlen - sb->last;
573
+}
574
+
575
+void sb_append(stringbuf *sb, const char *str)
576
+{
577
+ sb_append_len(sb, str, strlen(str));
578
+}
579
+
580
+void sb_append_len(stringbuf *sb, const char *str, int len)
581
+{
582
+ if (sb->remaining < len + 1) {
583
+ sb_realloc(sb, sb->last + len + 1 + SB_INCREMENT);
584
+ }
585
+ memcpy(sb->data + sb->last, str, len);
586
+ sb->data[sb->last + len] = 0;
587
+
588
+ sb->last += len;
589
+ sb->remaining -= len;
590
+#ifdef USE_UTF8
591
+ sb->chars += utf8_strlen(str, len);
592
+#endif
593
+}
594
+
595
+char *sb_to_string(stringbuf *sb)
596
+{
597
+ if (sb->data == NULL) {
598
+ /* Return an allocated empty string, not null */
599
+ return strdup("");
600
+ }
601
+ else {
602
+ /* Just return the data and free the stringbuf structure */
603
+ char *pt = sb->data;
604
+ free(sb);
605
+ return pt;
606
+ }
607
+}
608
+
609
+/* Insert and delete operations */
610
+
611
+/* Moves up all the data at position 'pos' and beyond by 'len' bytes
612
+ * to make room for new data
613
+ *
614
+ * Note: Does *not* update sb->chars
615
+ */
616
+static void sb_insert_space(stringbuf *sb, int pos, int len)
617
+{
618
+ assert(pos <= sb->last);
619
+
620
+ /* Make sure there is enough space */
621
+ if (sb->remaining < len) {
622
+ sb_realloc(sb, sb->last + len + SB_INCREMENT);
623
+ }
624
+ /* Now move it up */
625
+ memmove(sb->data + pos + len, sb->data + pos, sb->last - pos);
626
+ sb->last += len;
627
+ sb->remaining -= len;
628
+ /* And null terminate */
629
+ sb->data[sb->last] = 0;
630
+}
631
+
632
+/**
633
+ * Move down all the data from pos + len, effectively
634
+ * deleting the data at position 'pos' of length 'len'
635
+ */
636
+static void sb_delete_space(stringbuf *sb, int pos, int len)
637
+{
638
+ assert(pos < sb->last);
639
+ assert(pos + len <= sb->last);
640
+
641
+#ifdef USE_UTF8
642
+ sb->chars -= utf8_strlen(sb->data + pos, len);
643
+#endif
644
+
645
+ /* Now move it up */
646
+ memmove(sb->data + pos, sb->data + pos + len, sb->last - pos - len);
647
+ sb->last -= len;
648
+ sb->remaining += len;
649
+ /* And null terminate */
650
+ sb->data[sb->last] = 0;
651
+}
652
+
653
+void sb_insert(stringbuf *sb, int index, const char *str)
654
+{
655
+ if (index >= sb->last) {
656
+ /* Inserting after the end of the list appends. */
657
+ sb_append(sb, str);
658
+ }
659
+ else {
660
+ int len = strlen(str);
661
+
662
+ sb_insert_space(sb, index, len);
663
+ memcpy(sb->data + index, str, len);
664
+#ifdef USE_UTF8
665
+ sb->chars += utf8_strlen(str, len);
666
+#endif
667
+ }
668
+}
669
+
670
+/**
671
+ * Delete the bytes at index 'index' for length 'len'
672
+ * Has no effect if the index is past the end of the list.
673
+ */
674
+void sb_delete(stringbuf *sb, int index, int len)
675
+{
676
+ if (index < sb->last) {
677
+ char *pos = sb->data + index;
678
+ if (len < 0) {
679
+ len = sb->last;
680
+ }
681
+
682
+ sb_delete_space(sb, pos - sb->data, len);
683
+ }
684
+}
685
+
686
+void sb_clear(stringbuf *sb)
687
+{
688
+ if (sb->data) {
689
+ /* Null terminate */
690
+ sb->data[0] = 0;
691
+ sb->last = 0;
692
+#ifdef USE_UTF8
693
+ sb->chars = 0;
694
+#endif
695
+ }
696
+}
697
+#line 1 "linenoise.c"
1698
/* linenoise.c -- guerrilla line editing library against the idea that a
2699
* line editing lib needs to be 20,000 lines of C code.
3700
*
4701
* You can find the latest source code at:
5702
*
6
- * http://github.com/antirez/linenoise
703
+ * http://github.com/msteveb/linenoise
704
+ * (forked from http://github.com/antirez/linenoise)
7705
*
8706
* Does a number of crazy assumptions that happen to be true in 99.9999% of
9707
* the 2010 UNIX computers around.
10708
*
11709
* ------------------------------------------------------------------------
12710
*
13
- * Copyright (c) 2010-2016, Salvatore Sanfilippo <antirez at gmail dot com>
14
- * Copyright (c) 2010-2013, Pieter Noordhuis <pcnoordhuis at gmail dot com>
711
+ * Copyright (c) 2010, Salvatore Sanfilippo <antirez at gmail dot com>
712
+ * Copyright (c) 2010, Pieter Noordhuis <pcnoordhuis at gmail dot com>
713
+ * Copyright (c) 2011, Steve Bennett <steveb at workware dot net dot au>
15714
*
16715
* All rights reserved.
17716
*
18717
* Redistribution and use in source and binary forms, with or without
19718
* modification, are permitted provided that the following conditions are
@@ -42,211 +741,381 @@
42741
*
43742
* References:
44743
* - http://invisible-island.net/xterm/ctlseqs/ctlseqs.html
45744
* - http://www.3waylabs.com/nw/WWW/products/wizcon/vt220.html
46745
*
47
- * Todo list:
48
- * - Filter bogus Ctrl+<char> combinations.
49
- * - Win32 support
50
- *
51746
* Bloat:
52
- * - History search like Ctrl+r in readline?
747
+ * - Completion?
53748
*
749
+ * Unix/termios
750
+ * ------------
54751
* List of escape sequences used by this program, we do everything just
55
- * with three sequences. In order to be so cheap we may have some
752
+ * a few sequences. In order to be so cheap we may have some
56753
* flickering effect with some slow terminal, but the lesser sequences
57754
* the more compatible.
58755
*
59756
* EL (Erase Line)
60
- * Sequence: ESC [ n K
61
- * Effect: if n is 0 or missing, clear from cursor to end of line
62
- * Effect: if n is 1, clear from beginning of line to cursor
63
- * Effect: if n is 2, clear entire line
757
+ * Sequence: ESC [ 0 K
758
+ * Effect: clear from cursor to end of line
64759
*
65760
* CUF (CUrsor Forward)
66761
* Sequence: ESC [ n C
67762
* Effect: moves cursor forward n chars
68763
*
69
- * CUB (CUrsor Backward)
70
- * Sequence: ESC [ n D
71
- * Effect: moves cursor backward n chars
72
- *
73
- * The following is used to get the terminal width if getting
74
- * the width with the TIOCGWINSZ ioctl fails
75
- *
76
- * DSR (Device Status Report)
77
- * Sequence: ESC [ 6 n
78
- * Effect: reports the current cusor position as ESC [ n ; m R
79
- * where n is the row and m is the column
80
- *
81
- * When multi line mode is enabled, we also use an additional escape
82
- * sequence. However multi line editing is disabled by default.
83
- *
84
- * CUU (Cursor Up)
85
- * Sequence: ESC [ n A
86
- * Effect: moves cursor up of n chars.
87
- *
88
- * CUD (Cursor Down)
89
- * Sequence: ESC [ n B
90
- * Effect: moves cursor down of n chars.
91
- *
92
- * When linenoiseClearScreen() is called, two additional escape sequences
93
- * are used in order to clear the screen and position the cursor at home
94
- * position.
95
- *
96
- * CUP (Cursor position)
764
+ * CR (Carriage Return)
765
+ * Sequence: \r
766
+ * Effect: moves cursor to column 1
767
+ *
768
+ * The following are used to clear the screen: ESC [ H ESC [ 2 J
769
+ * This is actually composed of two sequences:
770
+ *
771
+ * cursorhome
97772
* Sequence: ESC [ H
98773
* Effect: moves the cursor to upper left corner
99774
*
100
- * ED (Erase display)
775
+ * ED2 (Clear entire screen)
101776
* Sequence: ESC [ 2 J
102777
* Effect: clear the whole screen
103778
*
779
+ * == For highlighting control characters, we also use the following two ==
780
+ * SO (enter StandOut)
781
+ * Sequence: ESC [ 7 m
782
+ * Effect: Uses some standout mode such as reverse video
783
+ *
784
+ * SE (Standout End)
785
+ * Sequence: ESC [ 0 m
786
+ * Effect: Exit standout mode
787
+ *
788
+ * == Only used if TIOCGWINSZ fails ==
789
+ * DSR/CPR (Report cursor position)
790
+ * Sequence: ESC [ 6 n
791
+ * Effect: reports current cursor position as ESC [ NNN ; MMM R
792
+ *
793
+ * == Only used in multiline mode ==
794
+ * CUU (Cursor Up)
795
+ * Sequence: ESC [ n A
796
+ * Effect: moves cursor up n chars.
797
+ *
798
+ * CUD (Cursor Down)
799
+ * Sequence: ESC [ n B
800
+ * Effect: moves cursor down n chars.
801
+ *
802
+ * win32/console
803
+ * -------------
804
+ * If __MINGW32__ is defined, the win32 console API is used.
805
+ * This could probably be made to work for the msvc compiler too.
806
+ * This support based in part on work by Jon Griffiths.
104807
*/
105808
809
+#ifdef _WIN32 /* Windows platform, either MinGW or Visual Studio (MSVC) */
810
+#include <windows.h>
811
+#include <fcntl.h>
812
+#define USE_WINCONSOLE
813
+#ifdef __MINGW32__
814
+#define HAVE_UNISTD_H
815
+#endif
816
+#else
106817
#include <termios.h>
818
+#include <sys/ioctl.h>
819
+#include <poll.h>
820
+#define USE_TERMIOS
821
+#define HAVE_UNISTD_H
822
+#endif
823
+
824
+#ifdef HAVE_UNISTD_H
107825
#include <unistd.h>
826
+#endif
108827
#include <stdlib.h>
828
+#include <stdarg.h>
109829
#include <stdio.h>
830
+#include <assert.h>
110831
#include <errno.h>
111832
#include <string.h>
833
+#include <signal.h>
112834
#include <stdlib.h>
113
-#include <ctype.h>
114
-#include <sys/stat.h>
115835
#include <sys/types.h>
116
-#include <sys/ioctl.h>
117
-#include <unistd.h>
836
+
837
+#if defined(_WIN32) && !defined(__MINGW32__)
838
+/* Microsoft headers don't like old POSIX names */
839
+#define strdup _strdup
840
+#define snprintf _snprintf
841
+#endif
842
+
118843
#include "linenoise.h"
844
+#ifndef STRINGBUF_H
845
+#include "stringbuf.h"
846
+#endif
847
+#ifndef UTF8_UTIL_H
848
+#include "utf8.h"
849
+#endif
119850
120851
#define LINENOISE_DEFAULT_HISTORY_MAX_LEN 100
121
-#define LINENOISE_MAX_LINE 4096
122
-static char *unsupported_term[] = {"dumb","cons25","emacs",NULL};
123
-static linenoiseCompletionCallback *completionCallback = NULL;
124
-static linenoiseHintsCallback *hintsCallback = NULL;
125
-static linenoiseFreeHintsCallback *freeHintsCallback = NULL;
126
-
127
-static struct termios orig_termios; /* In order to restore at exit.*/
128
-static int maskmode = 0; /* Show "***" instead of input. For passwords. */
129
-static int rawmode = 0; /* For atexit() function to check if restore is needed*/
130
-static int mlmode = 0; /* Multi line mode. Default is single line. */
131
-static int atexit_registered = 0; /* Register atexit just 1 time. */
852
+
853
+/* ctrl('A') -> 0x01 */
854
+#define ctrl(C) ((C) - '@')
855
+/* meta('a') -> 0xe1 */
856
+#define meta(C) ((C) | 0x80)
857
+
858
+/* Use -ve numbers here to co-exist with normal unicode chars */
859
+enum {
860
+ SPECIAL_NONE,
861
+ /* don't use -1 here since that indicates error */
862
+ SPECIAL_UP = -20,
863
+ SPECIAL_DOWN = -21,
864
+ SPECIAL_LEFT = -22,
865
+ SPECIAL_RIGHT = -23,
866
+ SPECIAL_DELETE = -24,
867
+ SPECIAL_HOME = -25,
868
+ SPECIAL_END = -26,
869
+ SPECIAL_INSERT = -27,
870
+ SPECIAL_PAGE_UP = -28,
871
+ SPECIAL_PAGE_DOWN = -29,
872
+
873
+ /* Some handy names for other special keycodes */
874
+ CHAR_ESCAPE = 27,
875
+ CHAR_DELETE = 127,
876
+};
877
+
132878
static int history_max_len = LINENOISE_DEFAULT_HISTORY_MAX_LEN;
133879
static int history_len = 0;
880
+static int history_index = 0;
134881
static char **history = NULL;
135882
136
-/* The linenoiseState structure represents the state during line editing.
137
- * We pass this state to functions implementing specific editing
138
- * functionalities. */
139
-struct linenoiseState {
140
- int ifd; /* Terminal stdin file descriptor. */
141
- int ofd; /* Terminal stdout file descriptor. */
142
- char *buf; /* Edited line buffer. */
143
- size_t buflen; /* Edited line buffer size. */
144
- const char *prompt; /* Prompt to display. */
145
- size_t plen; /* Prompt length. */
146
- size_t pos; /* Current cursor position. */
147
- size_t oldpos; /* Previous refresh cursor position. */
148
- size_t len; /* Current edited line length. */
149
- size_t cols; /* Number of columns in terminal. */
150
- size_t maxrows; /* Maximum num of rows used so far (multiline mode) */
151
- int history_index; /* The history index we are currently editing. */
152
-};
153
-
154
-enum KEY_ACTION{
155
- KEY_NULL = 0, /* NULL */
156
- CTRL_A = 1, /* Ctrl+a */
157
- CTRL_B = 2, /* Ctrl-b */
158
- CTRL_C = 3, /* Ctrl-c */
159
- CTRL_D = 4, /* Ctrl-d */
160
- CTRL_E = 5, /* Ctrl-e */
161
- CTRL_F = 6, /* Ctrl-f */
162
- CTRL_H = 8, /* Ctrl-h */
163
- TAB = 9, /* Tab */
164
- CTRL_K = 11, /* Ctrl+k */
165
- CTRL_L = 12, /* Ctrl+l */
166
- ENTER = 13, /* Enter */
167
- CTRL_N = 14, /* Ctrl-n */
168
- CTRL_P = 16, /* Ctrl-p */
169
- CTRL_T = 20, /* Ctrl-t */
170
- CTRL_U = 21, /* Ctrl+u */
171
- CTRL_W = 23, /* Ctrl+w */
172
- ESC = 27, /* Escape */
173
- BACKSPACE = 127 /* Backspace */
174
-};
175
-
176
-static void linenoiseAtExit(void);
177
-int linenoiseHistoryAdd(const char *line);
178
-static void refreshLine(struct linenoiseState *l);
179
-
180
-/* Debugging macro. */
181
-#if 0
182
-FILE *lndebug_fp = NULL;
183
-#define lndebug(...) \
184
- do { \
185
- if (lndebug_fp == NULL) { \
186
- lndebug_fp = fopen("/tmp/lndebug.txt","a"); \
187
- fprintf(lndebug_fp, \
188
- "[%d %d %d] p: %d, rows: %d, rpos: %d, max: %d, oldmax: %d\n", \
189
- (int)l->len,(int)l->pos,(int)l->oldpos,plen,rows,rpos, \
190
- (int)l->maxrows,old_rows); \
191
- } \
192
- fprintf(lndebug_fp, ", " __VA_ARGS__); \
193
- fflush(lndebug_fp); \
194
- } while (0)
195
-#else
196
-#define lndebug(fmt, ...)
197
-#endif
198
-
199
-/* ======================= Low level terminal handling ====================== */
200
-
201
-/* Enable "mask mode". When it is enabled, instead of the input that
202
- * the user is typing, the terminal will just display a corresponding
203
- * number of asterisks, like "****". This is useful for passwords and other
204
- * secrets that should not be displayed. */
205
-void linenoiseMaskModeEnable(void) {
206
- maskmode = 1;
207
-}
208
-
209
-/* Disable mask mode. */
210
-void linenoiseMaskModeDisable(void) {
211
- maskmode = 0;
212
-}
213
-
214
-/* Set if to use or not the multi line mode. */
215
-void linenoiseSetMultiLine(int ml) {
216
- mlmode = ml;
217
-}
218
-
219
-/* Return true if the terminal name is in the list of terminals we know are
220
- * not able to understand basic escape sequences. */
221
-static int isUnsupportedTerm(void) {
222
- char *term = getenv("TERM");
223
- int j;
224
-
225
- if (term == NULL) return 0;
226
- for (j = 0; unsupported_term[j]; j++)
227
- if (!strcasecmp(term,unsupported_term[j])) return 1;
228
- return 0;
229
-}
230
-
231
-/* Raw mode: 1960 magic shit. */
232
-static int enableRawMode(int fd) {
233
- struct termios raw;
234
-
235
- if (!isatty(STDIN_FILENO)) goto fatal;
883
+/* Structure to contain the status of the current (being edited) line */
884
+struct current {
885
+ stringbuf *buf; /* Current buffer. Always null terminated */
886
+ int pos; /* Cursor position, measured in chars */
887
+ int cols; /* Size of the window, in chars */
888
+ int nrows; /* How many rows are being used in multiline mode (>= 1) */
889
+ int rpos; /* The current row containing the cursor - multiline mode only */
890
+ int colsright; /* refreshLine() cached cols for insert_char() optimisation */
891
+ int colsleft; /* refreshLine() cached cols for remove_char() optimisation */
892
+ const char *prompt;
893
+ stringbuf *capture; /* capture buffer, or NULL for none. Always null terminated */
894
+ stringbuf *output; /* used only during refreshLine() - output accumulator */
895
+#if defined(USE_TERMIOS)
896
+ int fd; /* Terminal fd */
897
+#elif defined(USE_WINCONSOLE)
898
+ HANDLE outh; /* Console output handle */
899
+ HANDLE inh; /* Console input handle */
900
+ int rows; /* Screen rows */
901
+ int x; /* Current column during output */
902
+ int y; /* Current row */
903
+#ifdef USE_UTF8
904
+ #define UBUF_MAX_CHARS 132
905
+ WORD ubuf[UBUF_MAX_CHARS + 1]; /* Accumulates utf16 output - one extra for final surrogate pairs */
906
+ int ubuflen; /* length used in ubuf */
907
+ int ubufcols; /* how many columns are represented by the chars in ubuf? */
908
+#endif
909
+#endif
910
+};
911
+
912
+static int fd_read(struct current *current);
913
+static int getWindowSize(struct current *current);
914
+static void cursorDown(struct current *current, int n);
915
+static void cursorUp(struct current *current, int n);
916
+static void eraseEol(struct current *current);
917
+static void refreshLine(struct current *current);
918
+static void refreshLineAlt(struct current *current, const char *prompt, const char *buf, int cursor_pos);
919
+static void setCursorPos(struct current *current, int x);
920
+static void setOutputHighlight(struct current *current, const int *props, int nprops);
921
+static void set_current(struct current *current, const char *str);
922
+
923
+static int fd_isatty(struct current *current)
924
+{
925
+#ifdef USE_TERMIOS
926
+ return isatty(current->fd);
927
+#else
928
+ (void)current;
929
+ return 0;
930
+#endif
931
+}
932
+
933
+void linenoiseHistoryFree(void) {
934
+ if (history) {
935
+ int j;
936
+
937
+ for (j = 0; j < history_len; j++)
938
+ free(history[j]);
939
+ free(history);
940
+ history = NULL;
941
+ history_len = 0;
942
+ }
943
+}
944
+
945
+typedef enum {
946
+ EP_START, /* looking for ESC */
947
+ EP_ESC, /* looking for [ */
948
+ EP_DIGITS, /* parsing digits */
949
+ EP_PROPS, /* parsing digits or semicolons */
950
+ EP_END, /* ok */
951
+ EP_ERROR, /* error */
952
+} ep_state_t;
953
+
954
+struct esc_parser {
955
+ ep_state_t state;
956
+ int props[5]; /* properties are stored here */
957
+ int maxprops; /* size of the props[] array */
958
+ int numprops; /* number of properties found */
959
+ int termchar; /* terminator char, or 0 for any alpha */
960
+ int current; /* current (partial) property value */
961
+};
962
+
963
+/**
964
+ * Initialise the escape sequence parser at *parser.
965
+ *
966
+ * If termchar is 0 any alpha char terminates ok. Otherwise only the given
967
+ * char terminates successfully.
968
+ * Run the parser state machine with calls to parseEscapeSequence() for each char.
969
+ */
970
+static void initParseEscapeSeq(struct esc_parser *parser, int termchar)
971
+{
972
+ parser->state = EP_START;
973
+ parser->maxprops = sizeof(parser->props) / sizeof(*parser->props);
974
+ parser->numprops = 0;
975
+ parser->current = 0;
976
+ parser->termchar = termchar;
977
+}
978
+
979
+/**
980
+ * Pass character 'ch' into the state machine to parse:
981
+ * 'ESC' '[' <digits> (';' <digits>)* <termchar>
982
+ *
983
+ * The first character must be ESC.
984
+ * Returns the current state. The state machine is done when it returns either EP_END
985
+ * or EP_ERROR.
986
+ *
987
+ * On EP_END, the "property/attribute" values can be read from parser->props[]
988
+ * of length parser->numprops.
989
+ */
990
+static int parseEscapeSequence(struct esc_parser *parser, int ch)
991
+{
992
+ switch (parser->state) {
993
+ case EP_START:
994
+ parser->state = (ch == '\x1b') ? EP_ESC : EP_ERROR;
995
+ break;
996
+ case EP_ESC:
997
+ parser->state = (ch == '[') ? EP_DIGITS : EP_ERROR;
998
+ break;
999
+ case EP_PROPS:
1000
+ if (ch == ';') {
1001
+ parser->state = EP_DIGITS;
1002
+donedigits:
1003
+ if (parser->numprops + 1 < parser->maxprops) {
1004
+ parser->props[parser->numprops++] = parser->current;
1005
+ parser->current = 0;
1006
+ }
1007
+ break;
1008
+ }
1009
+ /* fall through */
1010
+ case EP_DIGITS:
1011
+ if (ch >= '0' && ch <= '9') {
1012
+ parser->current = parser->current * 10 + (ch - '0');
1013
+ parser->state = EP_PROPS;
1014
+ break;
1015
+ }
1016
+ /* must be terminator */
1017
+ if (parser->termchar != ch) {
1018
+ if (parser->termchar != 0 || !((ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z'))) {
1019
+ parser->state = EP_ERROR;
1020
+ break;
1021
+ }
1022
+ }
1023
+ parser->state = EP_END;
1024
+ goto donedigits;
1025
+ case EP_END:
1026
+ parser->state = EP_ERROR;
1027
+ break;
1028
+ case EP_ERROR:
1029
+ break;
1030
+ }
1031
+ return parser->state;
1032
+}
1033
+
1034
+/*#define DEBUG_REFRESHLINE*/
1035
+
1036
+#ifdef DEBUG_REFRESHLINE
1037
+#define DRL(ARGS...) fprintf(dfh, ARGS)
1038
+static FILE *dfh;
1039
+
1040
+static void DRL_CHAR(int ch)
1041
+{
1042
+ if (ch < ' ') {
1043
+ DRL("^%c", ch + '@');
1044
+ }
1045
+ else if (ch > 127) {
1046
+ DRL("\\u%04x", ch);
1047
+ }
1048
+ else {
1049
+ DRL("%c", ch);
1050
+ }
1051
+}
1052
+static void DRL_STR(const char *str)
1053
+{
1054
+ while (*str) {
1055
+ int ch;
1056
+ int n = utf8_tounicode(str, &ch);
1057
+ str += n;
1058
+ DRL_CHAR(ch);
1059
+ }
1060
+}
1061
+#else
1062
+#define DRL(...)
1063
+#define DRL_CHAR(ch)
1064
+#define DRL_STR(str)
1065
+#endif
1066
+
1067
+#if defined(USE_WINCONSOLE)
1068
+#include "linenoise-win32.c"
1069
+#endif
1070
+
1071
+#if defined(USE_TERMIOS)
1072
+static void linenoiseAtExit(void);
1073
+static struct termios orig_termios; /* in order to restore at exit */
1074
+static int rawmode = 0; /* for atexit() function to check if restore is needed*/
1075
+static int atexit_registered = 0; /* register atexit just 1 time */
1076
+
1077
+static const char *unsupported_term[] = {"dumb","cons25","emacs",NULL};
1078
+
1079
+static int isUnsupportedTerm(void) {
1080
+ char *term = getenv("TERM");
1081
+
1082
+ if (term) {
1083
+ int j;
1084
+ for (j = 0; unsupported_term[j]; j++) {
1085
+ if (strcmp(term, unsupported_term[j]) == 0) {
1086
+ return 1;
1087
+ }
1088
+ }
1089
+ }
1090
+ return 0;
1091
+}
1092
+
1093
+static int enableRawMode(struct current *current) {
1094
+ struct termios raw;
1095
+
1096
+ current->fd = STDIN_FILENO;
1097
+ current->cols = 0;
1098
+
1099
+ if (!isatty(current->fd) || isUnsupportedTerm() ||
1100
+ tcgetattr(current->fd, &orig_termios) == -1) {
1101
+fatal:
1102
+ errno = ENOTTY;
1103
+ return -1;
1104
+ }
1105
+
2361106
if (!atexit_registered) {
2371107
atexit(linenoiseAtExit);
2381108
atexit_registered = 1;
2391109
}
240
- if (tcgetattr(fd,&orig_termios) == -1) goto fatal;
2411110
2421111
raw = orig_termios; /* modify the original mode */
2431112
/* input modes: no break, no CR to NL, no parity check, no strip char,
2441113
* no start/stop output control. */
2451114
raw.c_iflag &= ~(BRKINT | ICRNL | INPCK | ISTRIP | IXON);
246
- /* output modes - disable post processing */
247
- raw.c_oflag &= ~(OPOST);
1115
+ /* output modes - actually, no need to disable post processing */
1116
+ /*raw.c_oflag &= ~(OPOST);*/
2481117
/* control modes - set 8 bit chars */
2491118
raw.c_cflag |= (CS8);
2501119
/* local modes - choing off, canonical off, no extended functions,
2511120
* no signal chars (^Z,^C) */
2521121
raw.c_lflag &= ~(ECHO | ICANON | IEXTEN | ISIG);
@@ -253,163 +1122,452 @@
2531122
/* control chars - set return condition: min number of bytes and timer.
2541123
* We want read to return every single byte, without timeout. */
2551124
raw.c_cc[VMIN] = 1; raw.c_cc[VTIME] = 0; /* 1 byte, no timer */
2561125
2571126
/* put terminal in raw mode after flushing */
258
- if (tcsetattr(fd,TCSAFLUSH,&raw) < 0) goto fatal;
1127
+ if (tcsetattr(current->fd,TCSADRAIN,&raw) < 0) {
1128
+ goto fatal;
1129
+ }
2591130
rawmode = 1;
2601131
return 0;
261
-
262
-fatal:
263
- errno = ENOTTY;
264
- return -1;
2651132
}
2661133
267
-static void disableRawMode(int fd) {
1134
+static void disableRawMode(struct current *current) {
2681135
/* Don't even check the return value as it's too late. */
269
- if (rawmode && tcsetattr(fd,TCSAFLUSH,&orig_termios) != -1)
1136
+ if (rawmode && tcsetattr(current->fd,TCSADRAIN,&orig_termios) != -1)
2701137
rawmode = 0;
2711138
}
2721139
273
-/* Use the ESC [6n escape sequence to query the horizontal cursor position
274
- * and return it. On error -1 is returned, on success the position of the
275
- * cursor. */
276
-static int getCursorPosition(int ifd, int ofd) {
277
- char buf[32];
278
- int cols, rows;
279
- unsigned int i = 0;
280
-
281
- /* Report cursor location */
282
- if (write(ofd, "\x1b[6n", 4) != 4) return -1;
283
-
284
- /* Read the response: ESC [ rows ; cols R */
285
- while (i < sizeof(buf)-1) {
286
- if (read(ifd,buf+i,1) != 1) break;
287
- if (buf[i] == 'R') break;
288
- i++;
289
- }
290
- buf[i] = '\0';
291
-
292
- /* Parse it. */
293
- if (buf[0] != ESC || buf[1] != '[') return -1;
294
- if (sscanf(buf+2,"%d;%d",&rows,&cols) != 2) return -1;
295
- return cols;
296
-}
297
-
298
-/* Try to get the number of columns in the current terminal, or assume 80
299
- * if it fails. */
300
-static int getColumns(int ifd, int ofd) {
1140
+/* At exit we'll try to fix the terminal to the initial conditions. */
1141
+static void linenoiseAtExit(void) {
1142
+ if (rawmode) {
1143
+ tcsetattr(STDIN_FILENO, TCSADRAIN, &orig_termios);
1144
+ }
1145
+ linenoiseHistoryFree();
1146
+}
1147
+
1148
+/* gcc/glibc insists that we care about the return code of write!
1149
+ * Clarification: This means that a void-cast like "(void) (EXPR)"
1150
+ * does not work.
1151
+ */
1152
+#define IGNORE_RC(EXPR) if (EXPR) {}
1153
+
1154
+/**
1155
+ * Output bytes directly, or accumulate output (if current->output is set)
1156
+ */
1157
+static void outputChars(struct current *current, const char *buf, int len)
1158
+{
1159
+ if (len < 0) {
1160
+ len = strlen(buf);
1161
+ }
1162
+ if (current->output) {
1163
+ sb_append_len(current->output, buf, len);
1164
+ }
1165
+ else {
1166
+ IGNORE_RC(write(current->fd, buf, len));
1167
+ }
1168
+}
1169
+
1170
+/* Like outputChars, but using printf-style formatting
1171
+ */
1172
+static void outputFormatted(struct current *current, const char *format, ...)
1173
+{
1174
+ va_list args;
1175
+ char buf[64];
1176
+ int n;
1177
+
1178
+ va_start(args, format);
1179
+ n = vsnprintf(buf, sizeof(buf), format, args);
1180
+ /* This will never happen because we are sure to use outputFormatted() only for short sequences */
1181
+ assert(n < (int)sizeof(buf));
1182
+ va_end(args);
1183
+ outputChars(current, buf, n);
1184
+}
1185
+
1186
+static void cursorToLeft(struct current *current)
1187
+{
1188
+ outputChars(current, "\r", -1);
1189
+}
1190
+
1191
+static void setOutputHighlight(struct current *current, const int *props, int nprops)
1192
+{
1193
+ outputChars(current, "\x1b[", -1);
1194
+ while (nprops--) {
1195
+ outputFormatted(current, "%d%c", *props, (nprops == 0) ? 'm' : ';');
1196
+ props++;
1197
+ }
1198
+}
1199
+
1200
+static void eraseEol(struct current *current)
1201
+{
1202
+ outputChars(current, "\x1b[0K", -1);
1203
+}
1204
+
1205
+static void setCursorPos(struct current *current, int x)
1206
+{
1207
+ if (x == 0) {
1208
+ cursorToLeft(current);
1209
+ }
1210
+ else {
1211
+ outputFormatted(current, "\r\x1b[%dC", x);
1212
+ }
1213
+}
1214
+
1215
+static void cursorUp(struct current *current, int n)
1216
+{
1217
+ if (n) {
1218
+ outputFormatted(current, "\x1b[%dA", n);
1219
+ }
1220
+}
1221
+
1222
+static void cursorDown(struct current *current, int n)
1223
+{
1224
+ if (n) {
1225
+ outputFormatted(current, "\x1b[%dB", n);
1226
+ }
1227
+}
1228
+
1229
+void linenoiseClearScreen(void)
1230
+{
1231
+ IGNORE_RC(write(STDOUT_FILENO, "\x1b[H\x1b[2J", 7));
1232
+}
1233
+
1234
+/**
1235
+ * Reads a char from 'fd', waiting at most 'timeout' milliseconds.
1236
+ *
1237
+ * A timeout of -1 means to wait forever.
1238
+ *
1239
+ * Returns -1 if no char is received within the time or an error occurs.
1240
+ */
1241
+static int fd_read_char(int fd, int timeout)
1242
+{
1243
+ struct pollfd p;
1244
+ unsigned char c;
1245
+
1246
+ p.fd = fd;
1247
+ p.events = POLLIN;
1248
+
1249
+ if (poll(&p, 1, timeout) == 0) {
1250
+ /* timeout */
1251
+ return -1;
1252
+ }
1253
+ if (read(fd, &c, 1) != 1) {
1254
+ return -1;
1255
+ }
1256
+ return c;
1257
+}
1258
+
1259
+/**
1260
+ * Reads a complete utf-8 character
1261
+ * and returns the unicode value, or -1 on error.
1262
+ */
1263
+static int fd_read(struct current *current)
1264
+{
1265
+#ifdef USE_UTF8
1266
+ char buf[MAX_UTF8_LEN];
1267
+ int n;
1268
+ int i;
1269
+ int c;
1270
+
1271
+ if (read(current->fd, &buf[0], 1) != 1) {
1272
+ return -1;
1273
+ }
1274
+ n = utf8_charlen(buf[0]);
1275
+ if (n < 1) {
1276
+ return -1;
1277
+ }
1278
+ for (i = 1; i < n; i++) {
1279
+ if (read(current->fd, &buf[i], 1) != 1) {
1280
+ return -1;
1281
+ }
1282
+ }
1283
+ /* decode and return the character */
1284
+ utf8_tounicode(buf, &c);
1285
+ return c;
1286
+#else
1287
+ return fd_read_char(current->fd, -1);
1288
+#endif
1289
+}
1290
+
1291
+
1292
+/**
1293
+ * Stores the current cursor column in '*cols'.
1294
+ * Returns 1 if OK, or 0 if failed to determine cursor pos.
1295
+ */
1296
+static int queryCursor(struct current *current, int* cols)
1297
+{
1298
+ struct esc_parser parser;
1299
+ int ch;
1300
+
1301
+ /* Should not be buffering this output, it needs to go immediately */
1302
+ assert(current->output == NULL);
1303
+
1304
+ /* control sequence - report cursor location */
1305
+ outputChars(current, "\x1b[6n", -1);
1306
+
1307
+ /* Parse the response: ESC [ rows ; cols R */
1308
+ initParseEscapeSeq(&parser, 'R');
1309
+ while ((ch = fd_read_char(current->fd, 100)) > 0) {
1310
+ switch (parseEscapeSequence(&parser, ch)) {
1311
+ default:
1312
+ continue;
1313
+ case EP_END:
1314
+ if (parser.numprops == 2 && parser.props[1] < 1000) {
1315
+ *cols = parser.props[1];
1316
+ return 1;
1317
+ }
1318
+ break;
1319
+ case EP_ERROR:
1320
+ break;
1321
+ }
1322
+ /* failed */
1323
+ break;
1324
+ }
1325
+ return 0;
1326
+}
1327
+
1328
+/**
1329
+ * Updates current->cols with the current window size (width)
1330
+ */
1331
+static int getWindowSize(struct current *current)
1332
+{
3011333
struct winsize ws;
3021334
303
- if (ioctl(1, TIOCGWINSZ, &ws) == -1 || ws.ws_col == 0) {
304
- /* ioctl() failed. Try to query the terminal itself. */
305
- int start, cols;
306
-
307
- /* Get the initial position so we can restore it later. */
308
- start = getCursorPosition(ifd,ofd);
309
- if (start == -1) goto failed;
310
-
311
- /* Go to right margin and get position. */
312
- if (write(ofd,"\x1b[999C",6) != 6) goto failed;
313
- cols = getCursorPosition(ifd,ofd);
314
- if (cols == -1) goto failed;
315
-
316
- /* Restore position. */
317
- if (cols > start) {
318
- char seq[32];
319
- snprintf(seq,32,"\x1b[%dD",cols-start);
320
- if (write(ofd,seq,strlen(seq)) == -1) {
321
- /* Can't recover... */
322
- }
323
- }
324
- return cols;
325
- } else {
326
- return ws.ws_col;
327
- }
328
-
329
-failed:
330
- return 80;
331
-}
332
-
333
-/* Clear the screen. Used to handle ctrl+l */
334
-void linenoiseClearScreen(void) {
335
- if (write(STDOUT_FILENO,"\x1b[H\x1b[2J",7) <= 0) {
336
- /* nothing to do, just to avoid warning. */
337
- }
338
-}
339
-
340
-/* Beep, used for completion when there is nothing to complete or when all
341
- * the choices were already shown. */
342
-static void linenoiseBeep(void) {
1335
+ if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &ws) == 0 && ws.ws_col != 0) {
1336
+ current->cols = ws.ws_col;
1337
+ return 0;
1338
+ }
1339
+
1340
+ /* Failed to query the window size. Perhaps we are on a serial terminal.
1341
+ * Try to query the width by sending the cursor as far to the right
1342
+ * and reading back the cursor position.
1343
+ * Note that this is only done once per call to linenoise rather than
1344
+ * every time the line is refreshed for efficiency reasons.
1345
+ *
1346
+ * In more detail, we:
1347
+ * (a) request current cursor position,
1348
+ * (b) move cursor far right,
1349
+ * (c) request cursor position again,
1350
+ * (d) at last move back to the old position.
1351
+ * This gives us the width without messing with the externally
1352
+ * visible cursor position.
1353
+ */
1354
+
1355
+ if (current->cols == 0) {
1356
+ int here;
1357
+
1358
+ /* If anything fails => default 80 */
1359
+ current->cols = 80;
1360
+
1361
+ /* (a) */
1362
+ if (queryCursor (current, &here)) {
1363
+ /* (b) */
1364
+ setCursorPos(current, 999);
1365
+
1366
+ /* (c). Note: If (a) succeeded, then (c) should as well.
1367
+ * For paranoia we still check and have a fallback action
1368
+ * for (d) in case of failure..
1369
+ */
1370
+ if (queryCursor (current, &current->cols)) {
1371
+ /* (d) Reset the cursor back to the original location. */
1372
+ if (current->cols > here) {
1373
+ setCursorPos(current, here);
1374
+ }
1375
+ }
1376
+ }
1377
+ }
1378
+
1379
+ return 0;
1380
+}
1381
+
1382
+/**
1383
+ * If CHAR_ESCAPE was received, reads subsequent
1384
+ * chars to determine if this is a known special key.
1385
+ *
1386
+ * Returns SPECIAL_NONE if unrecognised, or -1 if EOF.
1387
+ *
1388
+ * If no additional char is received within a short time,
1389
+ * CHAR_ESCAPE is returned.
1390
+ */
1391
+static int check_special(int fd)
1392
+{
1393
+ int c = fd_read_char(fd, 50);
1394
+ int c2;
1395
+
1396
+ if (c < 0) {
1397
+ return CHAR_ESCAPE;
1398
+ }
1399
+ else if (c >= 'a' && c <= 'z') {
1400
+ /* esc-a => meta-a */
1401
+ return meta(c);
1402
+ }
1403
+
1404
+ c2 = fd_read_char(fd, 50);
1405
+ if (c2 < 0) {
1406
+ return c2;
1407
+ }
1408
+ if (c == '[' || c == 'O') {
1409
+ /* Potential arrow key */
1410
+ switch (c2) {
1411
+ case 'A':
1412
+ return SPECIAL_UP;
1413
+ case 'B':
1414
+ return SPECIAL_DOWN;
1415
+ case 'C':
1416
+ return SPECIAL_RIGHT;
1417
+ case 'D':
1418
+ return SPECIAL_LEFT;
1419
+ case 'F':
1420
+ return SPECIAL_END;
1421
+ case 'H':
1422
+ return SPECIAL_HOME;
1423
+ }
1424
+ }
1425
+ if (c == '[' && c2 >= '1' && c2 <= '8') {
1426
+ /* extended escape */
1427
+ c = fd_read_char(fd, 50);
1428
+ if (c == '~') {
1429
+ switch (c2) {
1430
+ case '2':
1431
+ return SPECIAL_INSERT;
1432
+ case '3':
1433
+ return SPECIAL_DELETE;
1434
+ case '5':
1435
+ return SPECIAL_PAGE_UP;
1436
+ case '6':
1437
+ return SPECIAL_PAGE_DOWN;
1438
+ case '7':
1439
+ return SPECIAL_HOME;
1440
+ case '8':
1441
+ return SPECIAL_END;
1442
+ }
1443
+ }
1444
+ while (c != -1 && c != '~') {
1445
+ /* .e.g \e[12~ or '\e[11;2~ discard the complete sequence */
1446
+ c = fd_read_char(fd, 50);
1447
+ }
1448
+ }
1449
+
1450
+ return SPECIAL_NONE;
1451
+}
1452
+#endif
1453
+
1454
+static void clearOutputHighlight(struct current *current)
1455
+{
1456
+ int nohighlight = 0;
1457
+ setOutputHighlight(current, &nohighlight, 1);
1458
+}
1459
+
1460
+static void outputControlChar(struct current *current, char ch)
1461
+{
1462
+ int reverse = 7;
1463
+ setOutputHighlight(current, &reverse, 1);
1464
+ outputChars(current, "^", 1);
1465
+ outputChars(current, &ch, 1);
1466
+ clearOutputHighlight(current);
1467
+}
1468
+
1469
+#ifndef utf8_getchars
1470
+static int utf8_getchars(char *buf, int c)
1471
+{
1472
+#ifdef USE_UTF8
1473
+ return utf8_fromunicode(buf, c);
1474
+#else
1475
+ *buf = c;
1476
+ return 1;
1477
+#endif
1478
+}
1479
+#endif
1480
+
1481
+/**
1482
+ * Returns the unicode character at the given offset,
1483
+ * or -1 if none.
1484
+ */
1485
+static int get_char(struct current *current, int pos)
1486
+{
1487
+ if (pos >= 0 && pos < sb_chars(current->buf)) {
1488
+ int c;
1489
+ int i = utf8_index(sb_str(current->buf), pos);
1490
+ (void)utf8_tounicode(sb_str(current->buf) + i, &c);
1491
+ return c;
1492
+ }
1493
+ return -1;
1494
+}
1495
+
1496
+static int char_display_width(int ch)
1497
+{
1498
+ if (ch < ' ') {
1499
+ /* control chars take two positions */
1500
+ return 2;
1501
+ }
1502
+ else {
1503
+ return utf8_width(ch);
1504
+ }
1505
+}
1506
+
1507
+#ifndef NO_COMPLETION
1508
+static linenoiseCompletionCallback *completionCallback = NULL;
1509
+static void *completionUserdata = NULL;
1510
+static int showhints = 1;
1511
+static linenoiseHintsCallback *hintsCallback = NULL;
1512
+static linenoiseFreeHintsCallback *freeHintsCallback = NULL;
1513
+static void *hintsUserdata = NULL;
1514
+
1515
+static void beep(void) {
1516
+#ifdef USE_TERMIOS
3431517
fprintf(stderr, "\x7");
3441518
fflush(stderr);
1519
+#endif
3451520
}
3461521
347
-/* ============================== Completion ================================ */
348
-
349
-/* Free a list of completion option populated by linenoiseAddCompletion(). */
3501522
static void freeCompletions(linenoiseCompletions *lc) {
3511523
size_t i;
3521524
for (i = 0; i < lc->len; i++)
3531525
free(lc->cvec[i]);
354
- if (lc->cvec != NULL)
355
- free(lc->cvec);
1526
+ free(lc->cvec);
3561527
}
3571528
358
-/* This is an helper function for linenoiseEdit() and is called when the
359
- * user types the <tab> key in order to complete the string currently in the
360
- * input.
361
- *
362
- * The state of the editing is encapsulated into the pointed linenoiseState
363
- * structure as described in the structure definition. */
364
-static int completeLine(struct linenoiseState *ls) {
1529
+static int completeLine(struct current *current) {
3651530
linenoiseCompletions lc = { 0, NULL };
366
- int nread, nwritten;
367
- char c = 0;
1531
+ int c = 0;
3681532
369
- completionCallback(ls->buf,&lc);
1533
+ completionCallback(sb_str(current->buf),&lc,completionUserdata);
3701534
if (lc.len == 0) {
371
- linenoiseBeep();
1535
+ beep();
3721536
} else {
3731537
size_t stop = 0, i = 0;
3741538
3751539
while(!stop) {
3761540
/* Show completion or original buffer */
3771541
if (i < lc.len) {
378
- struct linenoiseState saved = *ls;
379
-
380
- ls->len = ls->pos = strlen(lc.cvec[i]);
381
- ls->buf = lc.cvec[i];
382
- refreshLine(ls);
383
- ls->len = saved.len;
384
- ls->pos = saved.pos;
385
- ls->buf = saved.buf;
1542
+ int chars = utf8_strlen(lc.cvec[i], -1);
1543
+ refreshLineAlt(current, current->prompt, lc.cvec[i], chars);
3861544
} else {
387
- refreshLine(ls);
1545
+ refreshLine(current);
3881546
}
3891547
390
- nread = read(ls->ifd,&c,1);
391
- if (nread <= 0) {
392
- freeCompletions(&lc);
393
- return -1;
1548
+ c = fd_read(current);
1549
+ if (c == -1) {
1550
+ break;
3941551
}
3951552
3961553
switch(c) {
397
- case 9: /* tab */
1554
+ case '\t': /* tab */
3981555
i = (i+1) % (lc.len+1);
399
- if (i == lc.len) linenoiseBeep();
1556
+ if (i == lc.len) beep();
4001557
break;
401
- case 27: /* escape */
1558
+ case CHAR_ESCAPE: /* escape */
4021559
/* Re-show original buffer */
403
- if (i < lc.len) refreshLine(ls);
1560
+ if (i < lc.len) {
1561
+ refreshLine(current);
1562
+ }
4041563
stop = 1;
4051564
break;
4061565
default:
4071566
/* Update buffer and return */
4081567
if (i < lc.len) {
409
- nwritten = snprintf(ls->buf,ls->buflen,"%s",lc.cvec[i]);
410
- ls->len = ls->pos = nwritten;
1568
+ set_current(current,lc.cvec[i]);
4111569
}
4121570
stop = 1;
4131571
break;
4141572
}
4151573
}
@@ -417,769 +1575,1126 @@
4171575
4181576
freeCompletions(&lc);
4191577
return c; /* Return last read character */
4201578
}
4211579
422
-/* Register a callback function to be called for tab-completion. */
423
-void linenoiseSetCompletionCallback(linenoiseCompletionCallback *fn) {
1580
+/* Register a callback function to be called for tab-completion.
1581
+ Returns the prior callback so that the caller may (if needed)
1582
+ restore it when done. */
1583
+linenoiseCompletionCallback * linenoiseSetCompletionCallback(linenoiseCompletionCallback *fn, void *userdata) {
1584
+ linenoiseCompletionCallback * old = completionCallback;
4241585
completionCallback = fn;
425
-}
426
-
427
-/* Register a hits function to be called to show hits to the user at the
428
- * right of the prompt. */
429
-void linenoiseSetHintsCallback(linenoiseHintsCallback *fn) {
430
- hintsCallback = fn;
431
-}
432
-
433
-/* Register a function to free the hints returned by the hints callback
434
- * registered with linenoiseSetHintsCallback(). */
435
-void linenoiseSetFreeHintsCallback(linenoiseFreeHintsCallback *fn) {
436
- freeHintsCallback = fn;
437
-}
438
-
439
-/* This function is used by the callback function registered by the user
440
- * in order to add completion options given the input string when the
441
- * user typed <tab>. See the example.c source code for a very easy to
442
- * understand example. */
1586
+ completionUserdata = userdata;
1587
+ return old;
1588
+}
1589
+
4431590
void linenoiseAddCompletion(linenoiseCompletions *lc, const char *str) {
444
- size_t len = strlen(str);
445
- char *copy, **cvec;
446
-
447
- copy = malloc(len+1);
448
- if (copy == NULL) return;
449
- memcpy(copy,str,len+1);
450
- cvec = realloc(lc->cvec,sizeof(char*)*(lc->len+1));
451
- if (cvec == NULL) {
452
- free(copy);
453
- return;
454
- }
455
- lc->cvec = cvec;
456
- lc->cvec[lc->len++] = copy;
457
-}
458
-
459
-/* =========================== Line editing ================================= */
460
-
461
-/* We define a very simple "append buffer" structure, that is an heap
462
- * allocated string where we can append to. This is useful in order to
463
- * write all the escape sequences in a buffer and flush them to the standard
464
- * output in a single call, to avoid flickering effects. */
465
-struct abuf {
466
- char *b;
467
- int len;
468
-};
469
-
470
-static void abInit(struct abuf *ab) {
471
- ab->b = NULL;
472
- ab->len = 0;
473
-}
474
-
475
-static void abAppend(struct abuf *ab, const char *s, int len) {
476
- char *new = realloc(ab->b,ab->len+len);
477
-
478
- if (new == NULL) return;
479
- memcpy(new+ab->len,s,len);
480
- ab->b = new;
481
- ab->len += len;
482
-}
483
-
484
-static void abFree(struct abuf *ab) {
485
- free(ab->b);
1591
+ lc->cvec = (char **)realloc(lc->cvec,sizeof(char*)*(lc->len+1));
1592
+ lc->cvec[lc->len++] = strdup(str);
1593
+}
1594
+
1595
+void linenoiseSetHintsCallback(linenoiseHintsCallback *callback, void *userdata)
1596
+{
1597
+ hintsCallback = callback;
1598
+ hintsUserdata = userdata;
1599
+}
1600
+
1601
+void linenoiseSetFreeHintsCallback(linenoiseFreeHintsCallback *callback)
1602
+{
1603
+ freeHintsCallback = callback;
1604
+}
1605
+
1606
+#endif
1607
+
1608
+
1609
+static const char *reduceSingleBuf(const char *buf, int availcols, int *cursor_pos)
1610
+{
1611
+ /* We have availcols columns available.
1612
+ * If necessary, strip chars off the front of buf until *cursor_pos
1613
+ * fits within availcols
1614
+ */
1615
+ int needcols = 0;
1616
+ int pos = 0;
1617
+ int new_cursor_pos = *cursor_pos;
1618
+ const char *pt = buf;
1619
+
1620
+ DRL("reduceSingleBuf: availcols=%d, cursor_pos=%d\n", availcols, *cursor_pos);
1621
+
1622
+ while (*pt) {
1623
+ int ch;
1624
+ int n = utf8_tounicode(pt, &ch);
1625
+ pt += n;
1626
+
1627
+ needcols += char_display_width(ch);
1628
+
1629
+ /* If we need too many cols, strip
1630
+ * chars off the front of buf to make it fit.
1631
+ * We keep 3 extra cols to the right of the cursor.
1632
+ * 2 for possible wide chars, 1 for the last column that
1633
+ * can't be used.
1634
+ */
1635
+ while (needcols >= availcols - 3) {
1636
+ n = utf8_tounicode(buf, &ch);
1637
+ buf += n;
1638
+ needcols -= char_display_width(ch);
1639
+ DRL_CHAR(ch);
1640
+
1641
+ /* and adjust the apparent cursor position */
1642
+ new_cursor_pos--;
1643
+
1644
+ if (buf == pt) {
1645
+ /* can't remove more than this */
1646
+ break;
1647
+ }
1648
+ }
1649
+
1650
+ if (pos++ == *cursor_pos) {
1651
+ break;
1652
+ }
1653
+
1654
+ }
1655
+ DRL("<snip>");
1656
+ DRL_STR(buf);
1657
+ DRL("\nafter reduce, needcols=%d, new_cursor_pos=%d\n", needcols, new_cursor_pos);
1658
+
1659
+ /* Done, now new_cursor_pos contains the adjusted cursor position
1660
+ * and buf points to he adjusted start
1661
+ */
1662
+ *cursor_pos = new_cursor_pos;
1663
+ return buf;
1664
+}
1665
+
1666
+static int mlmode = 0;
1667
+
1668
+void linenoiseSetMultiLine(int enableml)
1669
+{
1670
+ mlmode = enableml;
4861671
}
4871672
4881673
/* Helper of refreshSingleLine() and refreshMultiLine() to show hints
489
- * to the right of the prompt. */
490
-void refreshShowHints(struct abuf *ab, struct linenoiseState *l, int plen) {
491
- char seq[64];
492
- if (hintsCallback && plen+l->len < l->cols) {
493
- int color = -1, bold = 0;
494
- char *hint = hintsCallback(l->buf,&color,&bold);
1674
+ * to the right of the prompt.
1675
+ * Returns 1 if a hint was shown, or 0 if not
1676
+ * If 'display' is 0, does no output. Just returns the appropriate return code.
1677
+ */
1678
+static int refreshShowHints(struct current *current, const char *buf, int availcols, int display)
1679
+{
1680
+ int rc = 0;
1681
+ if (showhints && hintsCallback && availcols > 0) {
1682
+ int bold = 0;
1683
+ int color = -1;
1684
+ char *hint = hintsCallback(buf, &color, &bold, hintsUserdata);
4951685
if (hint) {
496
- int hintlen = strlen(hint);
497
- int hintmaxlen = l->cols-(plen+l->len);
498
- if (hintlen > hintmaxlen) hintlen = hintmaxlen;
499
- if (bold == 1 && color == -1) color = 37;
500
- if (color != -1 || bold != 0)
501
- snprintf(seq,64,"\033[%d;%d;49m",bold,color);
502
- else
503
- seq[0] = '\0';
504
- abAppend(ab,seq,strlen(seq));
505
- abAppend(ab,hint,hintlen);
506
- if (color != -1 || bold != 0)
507
- abAppend(ab,"\033[0m",4);
508
- /* Call the function to free the hint returned. */
509
- if (freeHintsCallback) freeHintsCallback(hint);
510
- }
511
- }
512
-}
513
-
514
-/* Single line low level line refresh.
515
- *
516
- * Rewrite the currently edited line accordingly to the buffer content,
517
- * cursor position, and number of columns of the terminal. */
518
-static void refreshSingleLine(struct linenoiseState *l) {
519
- char seq[64];
520
- size_t plen = strlen(l->prompt);
521
- int fd = l->ofd;
522
- char *buf = l->buf;
523
- size_t len = l->len;
524
- size_t pos = l->pos;
525
- struct abuf ab;
526
-
527
- while((plen+pos) >= l->cols) {
528
- buf++;
529
- len--;
530
- pos--;
531
- }
532
- while (plen+len > l->cols) {
533
- len--;
534
- }
535
-
536
- abInit(&ab);
537
- /* Cursor to left edge */
538
- snprintf(seq,64,"\r");
539
- abAppend(&ab,seq,strlen(seq));
540
- /* Write the prompt and the current buffer content */
541
- abAppend(&ab,l->prompt,strlen(l->prompt));
542
- if (maskmode == 1) {
543
- while (len--) abAppend(&ab,"*",1);
544
- } else {
545
- abAppend(&ab,buf,len);
546
- }
547
- /* Show hits if any. */
548
- refreshShowHints(&ab,l,plen);
549
- /* Erase to right */
550
- snprintf(seq,64,"\x1b[0K");
551
- abAppend(&ab,seq,strlen(seq));
552
- /* Move cursor to original position. */
553
- snprintf(seq,64,"\r\x1b[%dC", (int)(pos+plen));
554
- abAppend(&ab,seq,strlen(seq));
555
- if (write(fd,ab.b,ab.len) == -1) {} /* Can't recover from write error. */
556
- abFree(&ab);
557
-}
558
-
559
-/* Multi line low level line refresh.
560
- *
561
- * Rewrite the currently edited line accordingly to the buffer content,
562
- * cursor position, and number of columns of the terminal. */
563
-static void refreshMultiLine(struct linenoiseState *l) {
564
- char seq[64];
565
- int plen = strlen(l->prompt);
566
- int rows = (plen+l->len+l->cols-1)/l->cols; /* rows used by current buf. */
567
- int rpos = (plen+l->oldpos+l->cols)/l->cols; /* cursor relative row. */
568
- int rpos2; /* rpos after refresh. */
569
- int col; /* colum position, zero-based. */
570
- int old_rows = l->maxrows;
571
- int fd = l->ofd, j;
572
- struct abuf ab;
573
-
574
- /* Update maxrows if needed. */
575
- if (rows > (int)l->maxrows) l->maxrows = rows;
576
-
577
- /* First step: clear all the lines used before. To do so start by
578
- * going to the last row. */
579
- abInit(&ab);
580
- if (old_rows-rpos > 0) {
581
- lndebug("go down %d", old_rows-rpos);
582
- snprintf(seq,64,"\x1b[%dB", old_rows-rpos);
583
- abAppend(&ab,seq,strlen(seq));
584
- }
585
-
586
- /* Now for every row clear it, go up. */
587
- for (j = 0; j < old_rows-1; j++) {
588
- lndebug("clear+up");
589
- snprintf(seq,64,"\r\x1b[0K\x1b[1A");
590
- abAppend(&ab,seq,strlen(seq));
591
- }
592
-
593
- /* Clean the top line. */
594
- lndebug("clear");
595
- snprintf(seq,64,"\r\x1b[0K");
596
- abAppend(&ab,seq,strlen(seq));
597
-
598
- /* Write the prompt and the current buffer content */
599
- abAppend(&ab,l->prompt,strlen(l->prompt));
600
- if (maskmode == 1) {
601
- unsigned int i;
602
- for (i = 0; i < l->len; i++) abAppend(&ab,"*",1);
603
- } else {
604
- abAppend(&ab,l->buf,l->len);
605
- }
606
-
607
- /* Show hits if any. */
608
- refreshShowHints(&ab,l,plen);
609
-
610
- /* If we are at the very end of the screen with our prompt, we need to
611
- * emit a newline and move the prompt to the first column. */
612
- if (l->pos &&
613
- l->pos == l->len &&
614
- (l->pos+plen) % l->cols == 0)
615
- {
616
- lndebug("<newline>");
617
- abAppend(&ab,"\n",1);
618
- snprintf(seq,64,"\r");
619
- abAppend(&ab,seq,strlen(seq));
620
- rows++;
621
- if (rows > (int)l->maxrows) l->maxrows = rows;
622
- }
623
-
624
- /* Move cursor to right position. */
625
- rpos2 = (plen+l->pos+l->cols)/l->cols; /* current cursor relative row. */
626
- lndebug("rpos2 %d", rpos2);
627
-
628
- /* Go up till we reach the expected positon. */
629
- if (rows-rpos2 > 0) {
630
- lndebug("go-up %d", rows-rpos2);
631
- snprintf(seq,64,"\x1b[%dA", rows-rpos2);
632
- abAppend(&ab,seq,strlen(seq));
633
- }
634
-
635
- /* Set column. */
636
- col = (plen+(int)l->pos) % (int)l->cols;
637
- lndebug("set col %d", 1+col);
638
- if (col)
639
- snprintf(seq,64,"\r\x1b[%dC", col);
640
- else
641
- snprintf(seq,64,"\r");
642
- abAppend(&ab,seq,strlen(seq));
643
-
644
- lndebug("\n");
645
- l->oldpos = l->pos;
646
-
647
- if (write(fd,ab.b,ab.len) == -1) {} /* Can't recover from write error. */
648
- abFree(&ab);
649
-}
650
-
651
-/* Calls the two low level functions refreshSingleLine() or
652
- * refreshMultiLine() according to the selected mode. */
653
-static void refreshLine(struct linenoiseState *l) {
654
- if (mlmode)
655
- refreshMultiLine(l);
656
- else
657
- refreshSingleLine(l);
658
-}
659
-
660
-/* Insert the character 'c' at cursor current position.
661
- *
662
- * On error writing to the terminal -1 is returned, otherwise 0. */
663
-int linenoiseEditInsert(struct linenoiseState *l, char c) {
664
- if (l->len < l->buflen) {
665
- if (l->len == l->pos) {
666
- l->buf[l->pos] = c;
667
- l->pos++;
668
- l->len++;
669
- l->buf[l->len] = '\0';
670
- if ((!mlmode && l->plen+l->len < l->cols && !hintsCallback)) {
671
- /* Avoid a full update of the line in the
672
- * trivial case. */
673
- char d = (maskmode==1) ? '*' : c;
674
- if (write(l->ofd,&d,1) == -1) return -1;
675
- } else {
676
- refreshLine(l);
677
- }
678
- } else {
679
- memmove(l->buf+l->pos+1,l->buf+l->pos,l->len-l->pos);
680
- l->buf[l->pos] = c;
681
- l->len++;
682
- l->pos++;
683
- l->buf[l->len] = '\0';
684
- refreshLine(l);
685
- }
1686
+ rc = 1;
1687
+ if (display) {
1688
+ const char *pt;
1689
+ if (bold == 1 && color == -1) color = 37;
1690
+ if (bold || color > 0) {
1691
+ int props[3] = { bold, color, 49 }; /* bold, color, fgnormal */
1692
+ setOutputHighlight(current, props, 3);
1693
+ }
1694
+ DRL("<hint bold=%d,color=%d>", bold, color);
1695
+ pt = hint;
1696
+ while (*pt) {
1697
+ int ch;
1698
+ int n = utf8_tounicode(pt, &ch);
1699
+ int width = char_display_width(ch);
1700
+
1701
+ if (width >= availcols) {
1702
+ DRL("<hinteol>");
1703
+ break;
1704
+ }
1705
+ DRL_CHAR(ch);
1706
+
1707
+ availcols -= width;
1708
+ outputChars(current, pt, n);
1709
+ pt += n;
1710
+ }
1711
+ if (bold || color > 0) {
1712
+ clearOutputHighlight(current);
1713
+ }
1714
+ /* Call the function to free the hint returned. */
1715
+ if (freeHintsCallback) freeHintsCallback(hint, hintsUserdata);
1716
+ }
1717
+ }
1718
+ }
1719
+ return rc;
1720
+}
1721
+
1722
+#ifdef USE_TERMIOS
1723
+static void refreshStart(struct current *current)
1724
+{
1725
+ /* We accumulate all output here */
1726
+ assert(current->output == NULL);
1727
+ current->output = sb_alloc();
1728
+}
1729
+
1730
+static void refreshEnd(struct current *current)
1731
+{
1732
+ /* Output everything at once */
1733
+ IGNORE_RC(write(current->fd, sb_str(current->output), sb_len(current->output)));
1734
+ sb_free(current->output);
1735
+ current->output = NULL;
1736
+}
1737
+
1738
+static void refreshStartChars(struct current *current)
1739
+{
1740
+ (void)current;
1741
+}
1742
+
1743
+static void refreshNewline(struct current *current)
1744
+{
1745
+ DRL("<nl>");
1746
+ outputChars(current, "\n", 1);
1747
+}
1748
+
1749
+static void refreshEndChars(struct current *current)
1750
+{
1751
+ (void)current;
1752
+}
1753
+#endif
1754
+
1755
+static void refreshLineAlt(struct current *current, const char *prompt, const char *buf, int cursor_pos)
1756
+{
1757
+ int i;
1758
+ const char *pt;
1759
+ int displaycol;
1760
+ int displayrow;
1761
+ int visible;
1762
+ int currentpos;
1763
+ int notecursor;
1764
+ int cursorcol = 0;
1765
+ int cursorrow = 0;
1766
+ int hint;
1767
+ struct esc_parser parser;
1768
+
1769
+#ifdef DEBUG_REFRESHLINE
1770
+ dfh = fopen("linenoise.debuglog", "a");
1771
+#endif
1772
+
1773
+ /* Should intercept SIGWINCH. For now, just get the size every time */
1774
+ getWindowSize(current);
1775
+
1776
+ refreshStart(current);
1777
+
1778
+ DRL("wincols=%d, cursor_pos=%d, nrows=%d, rpos=%d\n", current->cols, cursor_pos, current->nrows, current->rpos);
1779
+
1780
+ /* Here is the plan:
1781
+ * (a) move the the bottom row, going down the appropriate number of lines
1782
+ * (b) move to beginning of line and erase the current line
1783
+ * (c) go up one line and do the same, until we have erased up to the first row
1784
+ * (d) output the prompt, counting cols and rows, taking into account escape sequences
1785
+ * (e) output the buffer, counting cols and rows
1786
+ * (e') when we hit the current pos, save the cursor position
1787
+ * (f) move the cursor to the saved cursor position
1788
+ * (g) save the current cursor row and number of rows
1789
+ */
1790
+
1791
+ /* (a) - The cursor is currently at row rpos */
1792
+ cursorDown(current, current->nrows - current->rpos - 1);
1793
+ DRL("<cud=%d>", current->nrows - current->rpos - 1);
1794
+
1795
+ /* (b), (c) - Erase lines upwards until we get to the first row */
1796
+ for (i = 0; i < current->nrows; i++) {
1797
+ if (i) {
1798
+ DRL("<cup>");
1799
+ cursorUp(current, 1);
1800
+ }
1801
+ DRL("<clearline>");
1802
+ cursorToLeft(current);
1803
+ eraseEol(current);
1804
+ }
1805
+ DRL("\n");
1806
+
1807
+ /* (d) First output the prompt. control sequences don't take up display space */
1808
+ pt = prompt;
1809
+ displaycol = 0; /* current display column */
1810
+ displayrow = 0; /* current display row */
1811
+ visible = 1;
1812
+
1813
+ refreshStartChars(current);
1814
+
1815
+ while (*pt) {
1816
+ int width;
1817
+ int ch;
1818
+ int n = utf8_tounicode(pt, &ch);
1819
+
1820
+ if (visible && ch == CHAR_ESCAPE) {
1821
+ /* The start of an escape sequence, so not visible */
1822
+ visible = 0;
1823
+ initParseEscapeSeq(&parser, 'm');
1824
+ DRL("<esc-seq-start>");
1825
+ }
1826
+
1827
+ if (ch == '\n' || ch == '\r') {
1828
+ /* treat both CR and NL the same and force wrap */
1829
+ refreshNewline(current);
1830
+ displaycol = 0;
1831
+ displayrow++;
1832
+ }
1833
+ else {
1834
+ width = visible * utf8_width(ch);
1835
+
1836
+ displaycol += width;
1837
+ if (displaycol >= current->cols) {
1838
+ /* need to wrap to the next line because of newline or if it doesn't fit
1839
+ * XXX this is a problem in single line mode
1840
+ */
1841
+ refreshNewline(current);
1842
+ displaycol = width;
1843
+ displayrow++;
1844
+ }
1845
+
1846
+ DRL_CHAR(ch);
1847
+#ifdef USE_WINCONSOLE
1848
+ if (visible) {
1849
+ outputChars(current, pt, n);
1850
+ }
1851
+#else
1852
+ outputChars(current, pt, n);
1853
+#endif
1854
+ }
1855
+ pt += n;
1856
+
1857
+ if (!visible) {
1858
+ switch (parseEscapeSequence(&parser, ch)) {
1859
+ case EP_END:
1860
+ visible = 1;
1861
+ setOutputHighlight(current, parser.props, parser.numprops);
1862
+ DRL("<esc-seq-end,numprops=%d>", parser.numprops);
1863
+ break;
1864
+ case EP_ERROR:
1865
+ DRL("<esc-seq-err>");
1866
+ visible = 1;
1867
+ break;
1868
+ }
1869
+ }
1870
+ }
1871
+
1872
+ /* Now we are at the first line with all lines erased */
1873
+ DRL("\nafter prompt: displaycol=%d, displayrow=%d\n", displaycol, displayrow);
1874
+
1875
+
1876
+ /* (e) output the buffer, counting cols and rows */
1877
+ if (mlmode == 0) {
1878
+ /* In this mode we may need to trim chars from the start of the buffer until the
1879
+ * cursor fits in the window.
1880
+ */
1881
+ pt = reduceSingleBuf(buf, current->cols - displaycol, &cursor_pos);
1882
+ }
1883
+ else {
1884
+ pt = buf;
1885
+ }
1886
+
1887
+ currentpos = 0;
1888
+ notecursor = -1;
1889
+
1890
+ while (*pt) {
1891
+ int ch;
1892
+ int n = utf8_tounicode(pt, &ch);
1893
+ int width = char_display_width(ch);
1894
+
1895
+ if (currentpos == cursor_pos) {
1896
+ /* (e') wherever we output this character is where we want the cursor */
1897
+ notecursor = 1;
1898
+ }
1899
+
1900
+ if (displaycol + width >= current->cols) {
1901
+ if (mlmode == 0) {
1902
+ /* In single line mode stop once we print as much as we can on one line */
1903
+ DRL("<slmode>");
1904
+ break;
1905
+ }
1906
+ /* need to wrap to the next line since it doesn't fit */
1907
+ refreshNewline(current);
1908
+ displaycol = 0;
1909
+ displayrow++;
1910
+ }
1911
+
1912
+ if (notecursor == 1) {
1913
+ /* (e') Save this position as the current cursor position */
1914
+ cursorcol = displaycol;
1915
+ cursorrow = displayrow;
1916
+ notecursor = 0;
1917
+ DRL("<cursor>");
1918
+ }
1919
+
1920
+ displaycol += width;
1921
+
1922
+ if (ch < ' ') {
1923
+ outputControlChar(current, ch + '@');
1924
+ }
1925
+ else {
1926
+ outputChars(current, pt, n);
1927
+ }
1928
+ DRL_CHAR(ch);
1929
+ if (width != 1) {
1930
+ DRL("<w=%d>", width);
1931
+ }
1932
+
1933
+ pt += n;
1934
+ currentpos++;
1935
+ }
1936
+
1937
+ /* If we didn't see the cursor, it is at the current location */
1938
+ if (notecursor) {
1939
+ DRL("<cursor>");
1940
+ cursorcol = displaycol;
1941
+ cursorrow = displayrow;
1942
+ }
1943
+
1944
+ DRL("\nafter buf: displaycol=%d, displayrow=%d, cursorcol=%d, cursorrow=%d\n", displaycol, displayrow, cursorcol, cursorrow);
1945
+
1946
+ /* (f) show hints */
1947
+ hint = refreshShowHints(current, buf, current->cols - displaycol, 1);
1948
+
1949
+ /* Remember how many many cols are available for insert optimisation */
1950
+ if (prompt == current->prompt && hint == 0) {
1951
+ current->colsright = current->cols - displaycol;
1952
+ current->colsleft = displaycol;
1953
+ }
1954
+ else {
1955
+ /* Can't optimise */
1956
+ current->colsright = 0;
1957
+ current->colsleft = 0;
1958
+ }
1959
+ DRL("\nafter hints: colsleft=%d, colsright=%d\n\n", current->colsleft, current->colsright);
1960
+
1961
+ refreshEndChars(current);
1962
+
1963
+ /* (g) move the cursor to the correct place */
1964
+ cursorUp(current, displayrow - cursorrow);
1965
+ setCursorPos(current, cursorcol);
1966
+
1967
+ /* (h) Update the number of rows if larger, but never reduce this */
1968
+ if (displayrow >= current->nrows) {
1969
+ current->nrows = displayrow + 1;
1970
+ }
1971
+ /* And remember the row that the cursor is on */
1972
+ current->rpos = cursorrow;
1973
+
1974
+ refreshEnd(current);
1975
+
1976
+#ifdef DEBUG_REFRESHLINE
1977
+ fclose(dfh);
1978
+#endif
1979
+}
1980
+
1981
+static void refreshLine(struct current *current)
1982
+{
1983
+ refreshLineAlt(current, current->prompt, sb_str(current->buf), current->pos);
1984
+}
1985
+
1986
+static void set_current(struct current *current, const char *str)
1987
+{
1988
+ sb_clear(current->buf);
1989
+ sb_append(current->buf, str);
1990
+ current->pos = sb_chars(current->buf);
1991
+}
1992
+
1993
+/**
1994
+ * Removes the char at 'pos'.
1995
+ *
1996
+ * Returns 1 if the line needs to be refreshed, 2 if not
1997
+ * and 0 if nothing was removed
1998
+ */
1999
+static int remove_char(struct current *current, int pos)
2000
+{
2001
+ if (pos >= 0 && pos < sb_chars(current->buf)) {
2002
+ int offset = utf8_index(sb_str(current->buf), pos);
2003
+ int nbytes = utf8_index(sb_str(current->buf) + offset, 1);
2004
+ int rc = 1;
2005
+
2006
+ /* Now we try to optimise in the simple but very common case that:
2007
+ * - outputChars() can be used directly (not win32)
2008
+ * - we are removing the char at EOL
2009
+ * - the buffer is not empty
2010
+ * - there are columns available to the left
2011
+ * - the char being deleted is not a wide or utf-8 character
2012
+ * - no hints are being shown
2013
+ */
2014
+ if (current->output && current->pos == pos + 1 && current->pos == sb_chars(current->buf) && pos > 0) {
2015
+#ifdef USE_UTF8
2016
+ /* Could implement utf8_prev_len() but simplest just to not optimise this case */
2017
+ char last = sb_str(current->buf)[offset];
2018
+#else
2019
+ char last = 0;
2020
+#endif
2021
+ if (current->colsleft > 0 && (last & 0x80) == 0) {
2022
+ /* Have cols on the left and not a UTF-8 char or continuation */
2023
+ /* Yes, can optimise */
2024
+ current->colsleft--;
2025
+ current->colsright++;
2026
+ rc = 2;
2027
+ }
2028
+ }
2029
+
2030
+ sb_delete(current->buf, offset, nbytes);
2031
+
2032
+ if (current->pos > pos) {
2033
+ current->pos--;
2034
+ }
2035
+ if (rc == 2) {
2036
+ if (refreshShowHints(current, sb_str(current->buf), current->colsright, 0)) {
2037
+ /* A hint needs to be shown, so can't optimise after all */
2038
+ rc = 1;
2039
+ }
2040
+ else {
2041
+ /* optimised output */
2042
+ outputChars(current, "\b \b", 3);
2043
+ }
2044
+ }
2045
+ return rc;
2046
+ return 1;
2047
+ }
2048
+ return 0;
2049
+}
2050
+
2051
+/**
2052
+ * Insert 'ch' at position 'pos'
2053
+ *
2054
+ * Returns 1 if the line needs to be refreshed, 2 if not
2055
+ * and 0 if nothing was inserted (no room)
2056
+ */
2057
+static int insert_char(struct current *current, int pos, int ch)
2058
+{
2059
+ if (pos >= 0 && pos <= sb_chars(current->buf)) {
2060
+ char buf[MAX_UTF8_LEN + 1];
2061
+ int offset = utf8_index(sb_str(current->buf), pos);
2062
+ int n = utf8_getchars(buf, ch);
2063
+ int rc = 1;
2064
+
2065
+ /* null terminate since sb_insert() requires it */
2066
+ buf[n] = 0;
2067
+
2068
+ /* Now we try to optimise in the simple but very common case that:
2069
+ * - outputChars() can be used directly (not win32)
2070
+ * - we are inserting at EOL
2071
+ * - there are enough columns available
2072
+ * - no hints are being shown
2073
+ */
2074
+ if (current->output && pos == current->pos && pos == sb_chars(current->buf)) {
2075
+ int width = char_display_width(ch);
2076
+ if (current->colsright > width) {
2077
+ /* Yes, can optimise */
2078
+ current->colsright -= width;
2079
+ current->colsleft -= width;
2080
+ rc = 2;
2081
+ }
2082
+ }
2083
+ sb_insert(current->buf, offset, buf);
2084
+ if (current->pos >= pos) {
2085
+ current->pos++;
2086
+ }
2087
+ if (rc == 2) {
2088
+ if (refreshShowHints(current, sb_str(current->buf), current->colsright, 0)) {
2089
+ /* A hint needs to be shown, so can't optimise after all */
2090
+ rc = 1;
2091
+ }
2092
+ else {
2093
+ /* optimised output */
2094
+ outputChars(current, buf, n);
2095
+ }
2096
+ }
2097
+ return rc;
6862098
}
6872099
return 0;
6882100
}
6892101
690
-/* Move cursor on the left. */
691
-void linenoiseEditMoveLeft(struct linenoiseState *l) {
692
- if (l->pos > 0) {
693
- l->pos--;
694
- refreshLine(l);
695
- }
696
-}
697
-
698
-/* Move cursor on the right. */
699
-void linenoiseEditMoveRight(struct linenoiseState *l) {
700
- if (l->pos != l->len) {
701
- l->pos++;
702
- refreshLine(l);
703
- }
704
-}
705
-
706
-/* Move cursor to the start of the line. */
707
-void linenoiseEditMoveHome(struct linenoiseState *l) {
708
- if (l->pos != 0) {
709
- l->pos = 0;
710
- refreshLine(l);
711
- }
712
-}
713
-
714
-/* Move cursor to the end of the line. */
715
-void linenoiseEditMoveEnd(struct linenoiseState *l) {
716
- if (l->pos != l->len) {
717
- l->pos = l->len;
718
- refreshLine(l);
719
- }
720
-}
721
-
722
-/* Substitute the currently edited line with the next or previous history
723
- * entry as specified by 'dir'. */
724
-#define LINENOISE_HISTORY_NEXT 0
725
-#define LINENOISE_HISTORY_PREV 1
726
-void linenoiseEditHistoryNext(struct linenoiseState *l, int dir) {
727
- if (history_len > 1) {
728
- /* Update the current history entry before to
729
- * overwrite it with the next one. */
730
- free(history[history_len - 1 - l->history_index]);
731
- history[history_len - 1 - l->history_index] = strdup(l->buf);
732
- /* Show the new entry */
733
- l->history_index += (dir == LINENOISE_HISTORY_PREV) ? 1 : -1;
734
- if (l->history_index < 0) {
735
- l->history_index = 0;
736
- return;
737
- } else if (l->history_index >= history_len) {
738
- l->history_index = history_len-1;
739
- return;
740
- }
741
- strncpy(l->buf,history[history_len - 1 - l->history_index],l->buflen);
742
- l->buf[l->buflen-1] = '\0';
743
- l->len = l->pos = strlen(l->buf);
744
- refreshLine(l);
745
- }
746
-}
747
-
748
-/* Delete the character at the right of the cursor without altering the cursor
749
- * position. Basically this is what happens with the "Delete" keyboard key. */
750
-void linenoiseEditDelete(struct linenoiseState *l) {
751
- if (l->len > 0 && l->pos < l->len) {
752
- memmove(l->buf+l->pos,l->buf+l->pos+1,l->len-l->pos-1);
753
- l->len--;
754
- l->buf[l->len] = '\0';
755
- refreshLine(l);
756
- }
757
-}
758
-
759
-/* Backspace implementation. */
760
-void linenoiseEditBackspace(struct linenoiseState *l) {
761
- if (l->pos > 0 && l->len > 0) {
762
- memmove(l->buf+l->pos-1,l->buf+l->pos,l->len-l->pos);
763
- l->pos--;
764
- l->len--;
765
- l->buf[l->len] = '\0';
766
- refreshLine(l);
767
- }
768
-}
769
-
770
-/* Delete the previosu word, maintaining the cursor at the start of the
771
- * current word. */
772
-void linenoiseEditDeletePrevWord(struct linenoiseState *l) {
773
- size_t old_pos = l->pos;
774
- size_t diff;
775
-
776
- while (l->pos > 0 && l->buf[l->pos-1] == ' ')
777
- l->pos--;
778
- while (l->pos > 0 && l->buf[l->pos-1] != ' ')
779
- l->pos--;
780
- diff = old_pos - l->pos;
781
- memmove(l->buf+l->pos,l->buf+old_pos,l->len-old_pos+1);
782
- l->len -= diff;
783
- refreshLine(l);
784
-}
785
-
786
-/* This function is the core of the line editing capability of linenoise.
787
- * It expects 'fd' to be already in "raw mode" so that every key pressed
788
- * will be returned ASAP to read().
789
- *
790
- * The resulting string is put into 'buf' when the user type enter, or
791
- * when ctrl+d is typed.
792
- *
793
- * The function returns the length of the current buffer. */
794
-static int linenoiseEdit(int stdin_fd, int stdout_fd, char *buf, size_t buflen, const char *prompt)
795
-{
796
- struct linenoiseState l;
797
-
798
- /* Populate the linenoise state that we pass to functions implementing
799
- * specific editing functionalities. */
800
- l.ifd = stdin_fd;
801
- l.ofd = stdout_fd;
802
- l.buf = buf;
803
- l.buflen = buflen;
804
- l.prompt = prompt;
805
- l.plen = strlen(prompt);
806
- l.oldpos = l.pos = 0;
807
- l.len = 0;
808
- l.cols = getColumns(stdin_fd, stdout_fd);
809
- l.maxrows = 0;
810
- l.history_index = 0;
811
-
812
- /* Buffer starts empty. */
813
- l.buf[0] = '\0';
814
- l.buflen--; /* Make sure there is always space for the nulterm */
815
-
816
- /* The latest history entry is always our current buffer, that
817
- * initially is just an empty string. */
818
- linenoiseHistoryAdd("");
819
-
820
- if (write(l.ofd,prompt,l.plen) == -1) return -1;
821
- while(1) {
822
- char c;
823
- int nread;
824
- char seq[3];
825
-
826
- nread = read(l.ifd,&c,1);
827
- if (nread <= 0) return l.len;
828
-
829
- /* Only autocomplete when the callback is set. It returns < 0 when
830
- * there was an error reading from fd. Otherwise it will return the
831
- * character that should be handled next. */
832
- if (c == 9 && completionCallback != NULL) {
833
- c = completeLine(&l);
834
- /* Return on errors */
835
- if (c < 0) return l.len;
836
- /* Read next character when 0 */
837
- if (c == 0) continue;
838
- }
839
-
840
- switch(c) {
841
- case ENTER: /* enter */
842
- history_len--;
843
- free(history[history_len]);
844
- if (mlmode) linenoiseEditMoveEnd(&l);
845
- if (hintsCallback) {
846
- /* Force a refresh without hints to leave the previous
847
- * line as the user typed it after a newline. */
848
- linenoiseHintsCallback *hc = hintsCallback;
849
- hintsCallback = NULL;
850
- refreshLine(&l);
851
- hintsCallback = hc;
852
- }
853
- return (int)l.len;
854
- case CTRL_C: /* ctrl-c */
855
- errno = EAGAIN;
856
- return -1;
857
- case BACKSPACE: /* backspace */
858
- case 8: /* ctrl-h */
859
- linenoiseEditBackspace(&l);
860
- break;
861
- case CTRL_D: /* ctrl-d, remove char at right of cursor, or if the
862
- line is empty, act as end-of-file. */
863
- if (l.len > 0) {
864
- linenoiseEditDelete(&l);
865
- } else {
866
- history_len--;
867
- free(history[history_len]);
868
- return -1;
869
- }
870
- break;
871
- case CTRL_T: /* ctrl-t, swaps current character with previous. */
872
- if (l.pos > 0 && l.pos < l.len) {
873
- int aux = buf[l.pos-1];
874
- buf[l.pos-1] = buf[l.pos];
875
- buf[l.pos] = aux;
876
- if (l.pos != l.len-1) l.pos++;
877
- refreshLine(&l);
878
- }
879
- break;
880
- case CTRL_B: /* ctrl-b */
881
- linenoiseEditMoveLeft(&l);
882
- break;
883
- case CTRL_F: /* ctrl-f */
884
- linenoiseEditMoveRight(&l);
885
- break;
886
- case CTRL_P: /* ctrl-p */
887
- linenoiseEditHistoryNext(&l, LINENOISE_HISTORY_PREV);
888
- break;
889
- case CTRL_N: /* ctrl-n */
890
- linenoiseEditHistoryNext(&l, LINENOISE_HISTORY_NEXT);
891
- break;
892
- case ESC: /* escape sequence */
893
- /* Read the next two bytes representing the escape sequence.
894
- * Use two calls to handle slow terminals returning the two
895
- * chars at different times. */
896
- if (read(l.ifd,seq,1) == -1) break;
897
- if (read(l.ifd,seq+1,1) == -1) break;
898
-
899
- /* ESC [ sequences. */
900
- if (seq[0] == '[') {
901
- if (seq[1] >= '0' && seq[1] <= '9') {
902
- /* Extended escape, read additional byte. */
903
- if (read(l.ifd,seq+2,1) == -1) break;
904
- if (seq[2] == '~') {
905
- switch(seq[1]) {
906
- case '3': /* Delete key. */
907
- linenoiseEditDelete(&l);
908
- break;
909
- }
910
- }
911
- } else {
912
- switch(seq[1]) {
913
- case 'A': /* Up */
914
- linenoiseEditHistoryNext(&l, LINENOISE_HISTORY_PREV);
915
- break;
916
- case 'B': /* Down */
917
- linenoiseEditHistoryNext(&l, LINENOISE_HISTORY_NEXT);
918
- break;
919
- case 'C': /* Right */
920
- linenoiseEditMoveRight(&l);
921
- break;
922
- case 'D': /* Left */
923
- linenoiseEditMoveLeft(&l);
924
- break;
925
- case 'H': /* Home */
926
- linenoiseEditMoveHome(&l);
927
- break;
928
- case 'F': /* End*/
929
- linenoiseEditMoveEnd(&l);
930
- break;
931
- }
932
- }
933
- }
934
-
935
- /* ESC O sequences. */
936
- else if (seq[0] == 'O') {
937
- switch(seq[1]) {
938
- case 'H': /* Home */
939
- linenoiseEditMoveHome(&l);
940
- break;
941
- case 'F': /* End*/
942
- linenoiseEditMoveEnd(&l);
943
- break;
944
- }
945
- }
946
- break;
947
- default:
948
- if (linenoiseEditInsert(&l,c)) return -1;
949
- break;
950
- case CTRL_U: /* Ctrl+u, delete the whole line. */
951
- buf[0] = '\0';
952
- l.pos = l.len = 0;
953
- refreshLine(&l);
954
- break;
955
- case CTRL_K: /* Ctrl+k, delete from current to end of line. */
956
- buf[l.pos] = '\0';
957
- l.len = l.pos;
958
- refreshLine(&l);
959
- break;
960
- case CTRL_A: /* Ctrl+a, go to the start of the line */
961
- linenoiseEditMoveHome(&l);
962
- break;
963
- case CTRL_E: /* ctrl+e, go to the end of the line */
964
- linenoiseEditMoveEnd(&l);
965
- break;
966
- case CTRL_L: /* ctrl+l, clear screen */
967
- linenoiseClearScreen();
968
- refreshLine(&l);
969
- break;
970
- case CTRL_W: /* ctrl+w, delete previous word */
971
- linenoiseEditDeletePrevWord(&l);
972
- break;
973
- }
974
- }
975
- return l.len;
976
-}
977
-
978
-/* This special mode is used by linenoise in order to print scan codes
979
- * on screen for debugging / development purposes. It is implemented
980
- * by the linenoise_example program using the --keycodes option. */
981
-void linenoisePrintKeyCodes(void) {
982
- char quit[4];
983
-
984
- printf("Linenoise key codes debugging mode.\n"
985
- "Press keys to see scan codes. Type 'quit' at any time to exit.\n");
986
- if (enableRawMode(STDIN_FILENO) == -1) return;
987
- memset(quit,' ',4);
988
- while(1) {
989
- char c;
990
- int nread;
991
-
992
- nread = read(STDIN_FILENO,&c,1);
993
- if (nread <= 0) continue;
994
- memmove(quit,quit+1,sizeof(quit)-1); /* shift string to left. */
995
- quit[sizeof(quit)-1] = c; /* Insert current char on the right. */
996
- if (memcmp(quit,"quit",sizeof(quit)) == 0) break;
997
-
998
- printf("'%c' %02x (%d) (type quit to exit)\n",
999
- isprint(c) ? c : '?', (int)c, (int)c);
1000
- printf("\r"); /* Go left edge manually, we are in raw mode. */
1001
- fflush(stdout);
1002
- }
1003
- disableRawMode(STDIN_FILENO);
1004
-}
1005
-
1006
-/* This function calls the line editing function linenoiseEdit() using
1007
- * the STDIN file descriptor set in raw mode. */
1008
-static int linenoiseRaw(char *buf, size_t buflen, const char *prompt) {
1009
- int count;
1010
-
1011
- if (buflen == 0) {
1012
- errno = EINVAL;
1013
- return -1;
1014
- }
1015
-
1016
- if (enableRawMode(STDIN_FILENO) == -1) return -1;
1017
- count = linenoiseEdit(STDIN_FILENO, STDOUT_FILENO, buf, buflen, prompt);
1018
- disableRawMode(STDIN_FILENO);
1019
- printf("\n");
1020
- return count;
1021
-}
1022
-
1023
-/* This function is called when linenoise() is called with the standard
1024
- * input file descriptor not attached to a TTY. So for example when the
1025
- * program using linenoise is called in pipe or with a file redirected
1026
- * to its standard input. In this case, we want to be able to return the
1027
- * line regardless of its length (by default we are limited to 4k). */
1028
-static char *linenoiseNoTTY(void) {
1029
- char *line = NULL;
1030
- size_t len = 0, maxlen = 0;
1031
-
1032
- while(1) {
1033
- int c;
1034
- if (len == maxlen) {
1035
- char *oldval = line;
1036
- if (maxlen == 0) maxlen = 16;
1037
- maxlen *= 2;
1038
- line = realloc(line,maxlen);
1039
- if (line == NULL) {
1040
- if (oldval) free(oldval);
1041
- return NULL;
1042
- }
1043
- }
1044
- c = fgetc(stdin);
1045
- if (c == EOF || c == '\n') {
1046
- if (c == EOF && len == 0) {
1047
- free(line);
1048
- return NULL;
1049
- } else {
1050
- line[len] = '\0';
1051
- return line;
1052
- }
1053
- } else {
1054
- line[len] = c;
1055
- len++;
1056
- }
1057
- }
1058
-}
1059
-
1060
-/* The high level function that is the main API of the linenoise library.
1061
- * This function checks if the terminal has basic capabilities, just checking
1062
- * for a blacklist of stupid terminals, and later either calls the line
1063
- * editing function or uses dummy fgets() so that you will be able to type
1064
- * something even in the most desperate of the conditions. */
1065
-char *linenoise(const char *prompt) {
1066
- char buf[LINENOISE_MAX_LINE];
1067
- int count;
1068
-
1069
- if (!isatty(STDIN_FILENO)) {
1070
- /* Not a tty: read from file / pipe. In this mode we don't want any
1071
- * limit to the line size, so we call a function to handle that. */
1072
- return linenoiseNoTTY();
1073
- } else if (isUnsupportedTerm()) {
1074
- size_t len;
1075
-
1076
- printf("%s",prompt);
1077
- fflush(stdout);
1078
- if (fgets(buf,LINENOISE_MAX_LINE,stdin) == NULL) return NULL;
1079
- len = strlen(buf);
1080
- while(len && (buf[len-1] == '\n' || buf[len-1] == '\r')) {
1081
- len--;
1082
- buf[len] = '\0';
1083
- }
1084
- return strdup(buf);
1085
- } else {
1086
- count = linenoiseRaw(buf,LINENOISE_MAX_LINE,prompt);
1087
- if (count == -1) return NULL;
1088
- return strdup(buf);
1089
- }
1090
-}
1091
-
1092
-/* This is just a wrapper the user may want to call in order to make sure
1093
- * the linenoise returned buffer is freed with the same allocator it was
1094
- * created with. Useful when the main program is using an alternative
1095
- * allocator. */
1096
-void linenoiseFree(void *ptr) {
1097
- free(ptr);
1098
-}
1099
-
1100
-/* ================================ History ================================= */
1101
-
1102
-/* Free the history, but does not reset it. Only used when we have to
1103
- * exit() to avoid memory leaks are reported by valgrind & co. */
1104
-static void freeHistory(void) {
1105
- if (history) {
1106
- int j;
1107
-
1108
- for (j = 0; j < history_len; j++)
1109
- free(history[j]);
1110
- free(history);
1111
- }
1112
-}
1113
-
1114
-/* At exit we'll try to fix the terminal to the initial conditions. */
1115
-static void linenoiseAtExit(void) {
1116
- disableRawMode(STDIN_FILENO);
1117
- freeHistory();
1118
-}
1119
-
1120
-/* This is the API call to add a new entry in the linenoise history.
1121
- * It uses a fixed array of char pointers that are shifted (memmoved)
1122
- * when the history max length is reached in order to remove the older
1123
- * entry and make room for the new one, so it is not exactly suitable for huge
1124
- * histories, but will work well for a few hundred of entries.
1125
- *
1126
- * Using a circular buffer is smarter, but a bit more complex to handle. */
1127
-int linenoiseHistoryAdd(const char *line) {
1128
- char *linecopy;
1129
-
1130
- if (history_max_len == 0) return 0;
1131
-
1132
- /* Initialization on first call. */
1133
- if (history == NULL) {
1134
- history = malloc(sizeof(char*)*history_max_len);
1135
- if (history == NULL) return 0;
1136
- memset(history,0,(sizeof(char*)*history_max_len));
1137
- }
1138
-
1139
- /* Don't add duplicated lines. */
1140
- if (history_len && !strcmp(history[history_len-1], line)) return 0;
1141
-
1142
- /* Add an heap allocated copy of the line in the history.
1143
- * If we reached the max length, remove the older line. */
1144
- linecopy = strdup(line);
1145
- if (!linecopy) return 0;
2102
+/**
2103
+ * Captures up to 'n' characters starting at 'pos' for the cut buffer.
2104
+ *
2105
+ * This replaces any existing characters in the cut buffer.
2106
+ */
2107
+static void capture_chars(struct current *current, int pos, int nchars)
2108
+{
2109
+ if (pos >= 0 && (pos + nchars - 1) < sb_chars(current->buf)) {
2110
+ int offset = utf8_index(sb_str(current->buf), pos);
2111
+ int nbytes = utf8_index(sb_str(current->buf) + offset, nchars);
2112
+
2113
+ if (nbytes > 0) {
2114
+ if (current->capture) {
2115
+ sb_clear(current->capture);
2116
+ }
2117
+ else {
2118
+ current->capture = sb_alloc();
2119
+ }
2120
+ sb_append_len(current->capture, sb_str(current->buf) + offset, nbytes);
2121
+ }
2122
+ }
2123
+}
2124
+
2125
+/**
2126
+ * Removes up to 'n' characters at cursor position 'pos'.
2127
+ *
2128
+ * Returns 0 if no chars were removed or non-zero otherwise.
2129
+ */
2130
+static int remove_chars(struct current *current, int pos, int n)
2131
+{
2132
+ int removed = 0;
2133
+
2134
+ /* First save any chars which will be removed */
2135
+ capture_chars(current, pos, n);
2136
+
2137
+ while (n-- && remove_char(current, pos)) {
2138
+ removed++;
2139
+ }
2140
+ return removed;
2141
+}
2142
+/**
2143
+ * Inserts the characters (string) 'chars' at the cursor position 'pos'.
2144
+ *
2145
+ * Returns 0 if no chars were inserted or non-zero otherwise.
2146
+ */
2147
+static int insert_chars(struct current *current, int pos, const char *chars)
2148
+{
2149
+ int inserted = 0;
2150
+
2151
+ while (*chars) {
2152
+ int ch;
2153
+ int n = utf8_tounicode(chars, &ch);
2154
+ if (insert_char(current, pos, ch) == 0) {
2155
+ break;
2156
+ }
2157
+ inserted++;
2158
+ pos++;
2159
+ chars += n;
2160
+ }
2161
+ return inserted;
2162
+}
2163
+
2164
+static int skip_space_nonspace(struct current *current, int dir, int check_is_space)
2165
+{
2166
+ int moved = 0;
2167
+ int checkoffset = (dir < 0) ? -1 : 0;
2168
+ int limit = (dir < 0) ? 0 : sb_chars(current->buf);
2169
+ while (current->pos != limit && (get_char(current, current->pos + checkoffset) == ' ') == check_is_space) {
2170
+ current->pos += dir;
2171
+ moved++;
2172
+ }
2173
+ return moved;
2174
+}
2175
+
2176
+static int skip_space(struct current *current, int dir)
2177
+{
2178
+ return skip_space_nonspace(current, dir, 1);
2179
+}
2180
+
2181
+static int skip_nonspace(struct current *current, int dir)
2182
+{
2183
+ return skip_space_nonspace(current, dir, 0);
2184
+}
2185
+
2186
+static void set_history_index(struct current *current, int new_index)
2187
+{
2188
+ if (history_len > 1) {
2189
+ /* Update the current history entry before to
2190
+ * overwrite it with the next one. */
2191
+ free(history[history_len - 1 - history_index]);
2192
+ history[history_len - 1 - history_index] = strdup(sb_str(current->buf));
2193
+ /* Show the new entry */
2194
+ history_index = new_index;
2195
+ if (history_index < 0) {
2196
+ history_index = 0;
2197
+ } else if (history_index >= history_len) {
2198
+ history_index = history_len - 1;
2199
+ } else {
2200
+ set_current(current, history[history_len - 1 - history_index]);
2201
+ refreshLine(current);
2202
+ }
2203
+ }
2204
+}
2205
+
2206
+/**
2207
+ * Returns the keycode to process, or 0 if none.
2208
+ */
2209
+static int reverseIncrementalSearch(struct current *current)
2210
+{
2211
+ /* Display the reverse-i-search prompt and process chars */
2212
+ char rbuf[50];
2213
+ char rprompt[80];
2214
+ int rchars = 0;
2215
+ int rlen = 0;
2216
+ int searchpos = history_len - 1;
2217
+ int c;
2218
+
2219
+ rbuf[0] = 0;
2220
+ while (1) {
2221
+ int n = 0;
2222
+ const char *p = NULL;
2223
+ int skipsame = 0;
2224
+ int searchdir = -1;
2225
+
2226
+ snprintf(rprompt, sizeof(rprompt), "(reverse-i-search)'%s': ", rbuf);
2227
+ refreshLineAlt(current, rprompt, sb_str(current->buf), current->pos);
2228
+ c = fd_read(current);
2229
+ if (c == ctrl('H') || c == CHAR_DELETE) {
2230
+ if (rchars) {
2231
+ int p_ind = utf8_index(rbuf, --rchars);
2232
+ rbuf[p_ind] = 0;
2233
+ rlen = strlen(rbuf);
2234
+ }
2235
+ continue;
2236
+ }
2237
+#ifdef USE_TERMIOS
2238
+ if (c == CHAR_ESCAPE) {
2239
+ c = check_special(current->fd);
2240
+ }
2241
+#endif
2242
+ if (c == ctrl('R')) {
2243
+ /* Search for the previous (earlier) match */
2244
+ if (searchpos > 0) {
2245
+ searchpos--;
2246
+ }
2247
+ skipsame = 1;
2248
+ }
2249
+ else if (c == ctrl('S')) {
2250
+ /* Search for the next (later) match */
2251
+ if (searchpos < history_len) {
2252
+ searchpos++;
2253
+ }
2254
+ searchdir = 1;
2255
+ skipsame = 1;
2256
+ }
2257
+ else if (c == ctrl('P') || c == SPECIAL_UP) {
2258
+ /* Exit Ctrl-R mode and go to the previous history line from the current search pos */
2259
+ set_history_index(current, history_len - searchpos);
2260
+ c = 0;
2261
+ break;
2262
+ }
2263
+ else if (c == ctrl('N') || c == SPECIAL_DOWN) {
2264
+ /* Exit Ctrl-R mode and go to the next history line from the current search pos */
2265
+ set_history_index(current, history_len - searchpos - 2);
2266
+ c = 0;
2267
+ break;
2268
+ }
2269
+ else if (c >= ' ' && c <= '~') {
2270
+ /* >= here to allow for null terminator */
2271
+ if (rlen >= (int)sizeof(rbuf) - MAX_UTF8_LEN) {
2272
+ continue;
2273
+ }
2274
+
2275
+ n = utf8_getchars(rbuf + rlen, c);
2276
+ rlen += n;
2277
+ rchars++;
2278
+ rbuf[rlen] = 0;
2279
+
2280
+ /* Adding a new char resets the search location */
2281
+ searchpos = history_len - 1;
2282
+ }
2283
+ else {
2284
+ /* Exit from incremental search mode */
2285
+ break;
2286
+ }
2287
+
2288
+ /* Now search through the history for a match */
2289
+ for (; searchpos >= 0 && searchpos < history_len; searchpos += searchdir) {
2290
+ p = strstr(history[searchpos], rbuf);
2291
+ if (p) {
2292
+ /* Found a match */
2293
+ if (skipsame && strcmp(history[searchpos], sb_str(current->buf)) == 0) {
2294
+ /* But it is identical, so skip it */
2295
+ continue;
2296
+ }
2297
+ /* Copy the matching line and set the cursor position */
2298
+ history_index = history_len - 1 - searchpos;
2299
+ set_current(current,history[searchpos]);
2300
+ current->pos = utf8_strlen(history[searchpos], p - history[searchpos]);
2301
+ break;
2302
+ }
2303
+ }
2304
+ if (!p && n) {
2305
+ /* No match, so don't add it */
2306
+ rchars--;
2307
+ rlen -= n;
2308
+ rbuf[rlen] = 0;
2309
+ }
2310
+ }
2311
+ if (c == ctrl('G') || c == ctrl('C')) {
2312
+ /* ctrl-g terminates the search with no effect */
2313
+ set_current(current, "");
2314
+ history_index = 0;
2315
+ c = 0;
2316
+ }
2317
+ else if (c == ctrl('J')) {
2318
+ /* ctrl-j terminates the search leaving the buffer in place */
2319
+ history_index = 0;
2320
+ c = 0;
2321
+ }
2322
+ /* Go process the char normally */
2323
+ refreshLine(current);
2324
+ return c;
2325
+}
2326
+
2327
+static int linenoiseEdit(struct current *current) {
2328
+ history_index = 0;
2329
+
2330
+ refreshLine(current);
2331
+
2332
+ while(1) {
2333
+ int c = fd_read(current);
2334
+
2335
+#ifndef NO_COMPLETION
2336
+ /* Only autocomplete when the callback is set. It returns < 0 when
2337
+ * there was an error reading from fd. Otherwise it will return the
2338
+ * character that should be handled next. */
2339
+ if (c == '\t' && current->pos == sb_chars(current->buf) && completionCallback != NULL) {
2340
+ c = completeLine(current);
2341
+ }
2342
+#endif
2343
+ if (c == ctrl('R')) {
2344
+ /* reverse incremental search will provide an alternative keycode or 0 for none */
2345
+ c = reverseIncrementalSearch(current);
2346
+ /* go on to process the returned char normally */
2347
+ }
2348
+
2349
+#ifdef USE_TERMIOS
2350
+ if (c == CHAR_ESCAPE) { /* escape sequence */
2351
+ c = check_special(current->fd);
2352
+ }
2353
+#endif
2354
+ if (c == -1) {
2355
+ /* Return on errors */
2356
+ return sb_len(current->buf);
2357
+ }
2358
+
2359
+ switch(c) {
2360
+ case SPECIAL_NONE:
2361
+ break;
2362
+ case '\r': /* enter/CR */
2363
+ case '\n': /* LF */
2364
+ history_len--;
2365
+ free(history[history_len]);
2366
+ current->pos = sb_chars(current->buf);
2367
+ if (mlmode || hintsCallback) {
2368
+ showhints = 0;
2369
+ refreshLine(current);
2370
+ showhints = 1;
2371
+ }
2372
+ return sb_len(current->buf);
2373
+ case ctrl('C'): /* ctrl-c */
2374
+ errno = EAGAIN;
2375
+ return -1;
2376
+ case ctrl('Z'): /* ctrl-z */
2377
+#ifdef SIGTSTP
2378
+ /* send ourselves SIGSUSP */
2379
+ disableRawMode(current);
2380
+ raise(SIGTSTP);
2381
+ /* and resume */
2382
+ enableRawMode(current);
2383
+ refreshLine(current);
2384
+#endif
2385
+ continue;
2386
+ case CHAR_DELETE: /* backspace */
2387
+ case ctrl('H'):
2388
+ if (remove_char(current, current->pos - 1) == 1) {
2389
+ refreshLine(current);
2390
+ }
2391
+ break;
2392
+ case ctrl('D'): /* ctrl-d */
2393
+ if (sb_len(current->buf) == 0) {
2394
+ /* Empty line, so EOF */
2395
+ history_len--;
2396
+ free(history[history_len]);
2397
+ return -1;
2398
+ }
2399
+ /* Otherwise fall through to delete char to right of cursor */
2400
+ /* fall-thru */
2401
+ case SPECIAL_DELETE:
2402
+ if (remove_char(current, current->pos) == 1) {
2403
+ refreshLine(current);
2404
+ }
2405
+ break;
2406
+ case SPECIAL_INSERT:
2407
+ /* Ignore. Expansion Hook.
2408
+ * Future possibility: Toggle Insert/Overwrite Modes
2409
+ */
2410
+ break;
2411
+ case meta('b'): /* meta-b, move word left */
2412
+ if (skip_nonspace(current, -1)) {
2413
+ refreshLine(current);
2414
+ }
2415
+ else if (skip_space(current, -1)) {
2416
+ skip_nonspace(current, -1);
2417
+ refreshLine(current);
2418
+ }
2419
+ break;
2420
+ case meta('f'): /* meta-f, move word right */
2421
+ if (skip_space(current, 1)) {
2422
+ refreshLine(current);
2423
+ }
2424
+ else if (skip_nonspace(current, 1)) {
2425
+ skip_space(current, 1);
2426
+ refreshLine(current);
2427
+ }
2428
+ break;
2429
+ case ctrl('W'): /* ctrl-w, delete word at left. save deleted chars */
2430
+ /* eat any spaces on the left */
2431
+ {
2432
+ int pos = current->pos;
2433
+ while (pos > 0 && get_char(current, pos - 1) == ' ') {
2434
+ pos--;
2435
+ }
2436
+
2437
+ /* now eat any non-spaces on the left */
2438
+ while (pos > 0 && get_char(current, pos - 1) != ' ') {
2439
+ pos--;
2440
+ }
2441
+
2442
+ if (remove_chars(current, pos, current->pos - pos)) {
2443
+ refreshLine(current);
2444
+ }
2445
+ }
2446
+ break;
2447
+ case ctrl('T'): /* ctrl-t */
2448
+ if (current->pos > 0 && current->pos <= sb_chars(current->buf)) {
2449
+ /* If cursor is at end, transpose the previous two chars */
2450
+ int fixer = (current->pos == sb_chars(current->buf));
2451
+ c = get_char(current, current->pos - fixer);
2452
+ remove_char(current, current->pos - fixer);
2453
+ insert_char(current, current->pos - 1, c);
2454
+ refreshLine(current);
2455
+ }
2456
+ break;
2457
+ case ctrl('V'): /* ctrl-v */
2458
+ /* Insert the ^V first */
2459
+ if (insert_char(current, current->pos, c)) {
2460
+ refreshLine(current);
2461
+ /* Now wait for the next char. Can insert anything except \0 */
2462
+ c = fd_read(current);
2463
+
2464
+ /* Remove the ^V first */
2465
+ remove_char(current, current->pos - 1);
2466
+ if (c > 0) {
2467
+ /* Insert the actual char, can't be error or null */
2468
+ insert_char(current, current->pos, c);
2469
+ }
2470
+ refreshLine(current);
2471
+ }
2472
+ break;
2473
+ case ctrl('B'):
2474
+ case SPECIAL_LEFT:
2475
+ if (current->pos > 0) {
2476
+ current->pos--;
2477
+ refreshLine(current);
2478
+ }
2479
+ break;
2480
+ case ctrl('F'):
2481
+ case SPECIAL_RIGHT:
2482
+ if (current->pos < sb_chars(current->buf)) {
2483
+ current->pos++;
2484
+ refreshLine(current);
2485
+ }
2486
+ break;
2487
+ case SPECIAL_PAGE_UP: /* move to start of history */
2488
+ set_history_index(current, history_len - 1);
2489
+ break;
2490
+ case SPECIAL_PAGE_DOWN: /* move to 0 == end of history, i.e. current */
2491
+ set_history_index(current, 0);
2492
+ break;
2493
+ case ctrl('P'):
2494
+ case SPECIAL_UP:
2495
+ set_history_index(current, history_index + 1);
2496
+ break;
2497
+ case ctrl('N'):
2498
+ case SPECIAL_DOWN:
2499
+ set_history_index(current, history_index - 1);
2500
+ break;
2501
+ case ctrl('A'): /* Ctrl+a, go to the start of the line */
2502
+ case SPECIAL_HOME:
2503
+ current->pos = 0;
2504
+ refreshLine(current);
2505
+ break;
2506
+ case ctrl('E'): /* ctrl+e, go to the end of the line */
2507
+ case SPECIAL_END:
2508
+ current->pos = sb_chars(current->buf);
2509
+ refreshLine(current);
2510
+ break;
2511
+ case ctrl('U'): /* Ctrl+u, delete to beginning of line, save deleted chars. */
2512
+ if (remove_chars(current, 0, current->pos)) {
2513
+ refreshLine(current);
2514
+ }
2515
+ break;
2516
+ case ctrl('K'): /* Ctrl+k, delete from current to end of line, save deleted chars. */
2517
+ if (remove_chars(current, current->pos, sb_chars(current->buf) - current->pos)) {
2518
+ refreshLine(current);
2519
+ }
2520
+ break;
2521
+ case ctrl('Y'): /* Ctrl+y, insert saved chars at current position */
2522
+ if (current->capture && insert_chars(current, current->pos, sb_str(current->capture))) {
2523
+ refreshLine(current);
2524
+ }
2525
+ break;
2526
+ case ctrl('L'): /* Ctrl+L, clear screen */
2527
+ linenoiseClearScreen();
2528
+ /* Force recalc of window size for serial terminals */
2529
+ current->cols = 0;
2530
+ current->rpos = 0;
2531
+ refreshLine(current);
2532
+ break;
2533
+ default:
2534
+ if (c >= meta('a') && c <= meta('z')) {
2535
+ /* Don't insert meta chars that are not bound */
2536
+ break;
2537
+ }
2538
+ /* Only tab is allowed without ^V */
2539
+ if (c == '\t' || c >= ' ') {
2540
+ if (insert_char(current, current->pos, c) == 1) {
2541
+ refreshLine(current);
2542
+ }
2543
+ }
2544
+ break;
2545
+ }
2546
+ }
2547
+ return sb_len(current->buf);
2548
+}
2549
+
2550
+int linenoiseColumns(void)
2551
+{
2552
+ struct current current;
2553
+ current.output = NULL;
2554
+ enableRawMode (&current);
2555
+ getWindowSize (&current);
2556
+ disableRawMode (&current);
2557
+ return current.cols;
2558
+}
2559
+
2560
+/**
2561
+ * Reads a line from the file handle (without the trailing NL or CRNL)
2562
+ * and returns it in a stringbuf.
2563
+ * Returns NULL if no characters are read before EOF or error.
2564
+ *
2565
+ * Note that the character count will *not* be correct for lines containing
2566
+ * utf8 sequences. Do not rely on the character count.
2567
+ */
2568
+static stringbuf *sb_getline(FILE *fh)
2569
+{
2570
+ stringbuf *sb = sb_alloc();
2571
+ int c;
2572
+ int n = 0;
2573
+
2574
+ while ((c = getc(fh)) != EOF) {
2575
+ char ch;
2576
+ n++;
2577
+ if (c == '\r') {
2578
+ /* CRLF -> LF */
2579
+ continue;
2580
+ }
2581
+ if (c == '\n' || c == '\r') {
2582
+ break;
2583
+ }
2584
+ ch = c;
2585
+ /* ignore the effect of character count for partial utf8 sequences */
2586
+ sb_append_len(sb, &ch, 1);
2587
+ }
2588
+ if (n == 0 || sb->data == NULL) {
2589
+ sb_free(sb);
2590
+ return NULL;
2591
+ }
2592
+ return sb;
2593
+}
2594
+
2595
+char *linenoiseWithInitial(const char *prompt, const char *initial)
2596
+{
2597
+ int count;
2598
+ struct current current;
2599
+ stringbuf *sb;
2600
+
2601
+ memset(&current, 0, sizeof(current));
2602
+
2603
+ if (enableRawMode(&current) == -1) {
2604
+ printf("%s", prompt);
2605
+ fflush(stdout);
2606
+ sb = sb_getline(stdin);
2607
+ if (sb && !fd_isatty(&current)) {
2608
+ printf("%s\n", sb_str(sb));
2609
+ fflush(stdout);
2610
+ }
2611
+ }
2612
+ else {
2613
+ current.buf = sb_alloc();
2614
+ current.pos = 0;
2615
+ current.nrows = 1;
2616
+ current.prompt = prompt;
2617
+
2618
+ /* The latest history entry is always our current buffer */
2619
+ linenoiseHistoryAdd(initial);
2620
+ set_current(&current, initial);
2621
+
2622
+ count = linenoiseEdit(&current);
2623
+
2624
+ disableRawMode(&current);
2625
+ printf("\n");
2626
+
2627
+ sb_free(current.capture);
2628
+ if (count == -1) {
2629
+ sb_free(current.buf);
2630
+ return NULL;
2631
+ }
2632
+ sb = current.buf;
2633
+ }
2634
+ return sb ? sb_to_string(sb) : NULL;
2635
+}
2636
+
2637
+char *linenoise(const char *prompt)
2638
+{
2639
+ return linenoiseWithInitial(prompt, "");
2640
+}
2641
+
2642
+/* Using a circular buffer is smarter, but a bit more complex to handle. */
2643
+static int linenoiseHistoryAddAllocated(char *line) {
2644
+
2645
+ if (history_max_len == 0) {
2646
+notinserted:
2647
+ free(line);
2648
+ return 0;
2649
+ }
2650
+ if (history == NULL) {
2651
+ history = (char **)calloc(sizeof(char*), history_max_len);
2652
+ }
2653
+
2654
+ /* do not insert duplicate lines into history */
2655
+ if (history_len > 0 && strcmp(line, history[history_len - 1]) == 0) {
2656
+ goto notinserted;
2657
+ }
2658
+
11462659
if (history_len == history_max_len) {
11472660
free(history[0]);
11482661
memmove(history,history+1,sizeof(char*)*(history_max_len-1));
11492662
history_len--;
11502663
}
1151
- history[history_len] = linecopy;
2664
+ history[history_len] = line;
11522665
history_len++;
11532666
return 1;
11542667
}
11552668
1156
-/* Set the maximum length for the history. This function can be called even
1157
- * if there is already some history, the function will make sure to retain
1158
- * just the latest 'len' elements if the new history length value is smaller
1159
- * than the amount of items already inside the history. */
2669
+int linenoiseHistoryAdd(const char *line) {
2670
+ return linenoiseHistoryAddAllocated(strdup(line));
2671
+}
2672
+
2673
+int linenoiseHistoryGetMaxLen(void) {
2674
+ return history_max_len;
2675
+}
2676
+
11602677
int linenoiseHistorySetMaxLen(int len) {
1161
- char **new;
2678
+ char **newHistory;
11622679
11632680
if (len < 1) return 0;
11642681
if (history) {
11652682
int tocopy = history_len;
11662683
1167
- new = malloc(sizeof(char*)*len);
1168
- if (new == NULL) return 0;
2684
+ newHistory = (char **)calloc(sizeof(char*), len);
11692685
11702686
/* If we can't copy everything, free the elements we'll not use. */
11712687
if (len < tocopy) {
11722688
int j;
11732689
11742690
for (j = 0; j < tocopy-len; j++) free(history[j]);
11752691
tocopy = len;
11762692
}
1177
- memset(new,0,sizeof(char*)*len);
1178
- memcpy(new,history+(history_len-tocopy), sizeof(char*)*tocopy);
2693
+ memcpy(newHistory,history+(history_len-tocopy), sizeof(char*)*tocopy);
11792694
free(history);
1180
- history = new;
2695
+ history = newHistory;
11812696
}
11822697
history_max_len = len;
11832698
if (history_len > history_max_len)
11842699
history_len = history_max_len;
11852700
return 1;
@@ -1186,41 +2701,86 @@
11862701
}
11872702
11882703
/* Save the history in the specified file. On success 0 is returned
11892704
* otherwise -1 is returned. */
11902705
int linenoiseHistorySave(const char *filename) {
1191
- mode_t old_umask = umask(S_IXUSR|S_IRWXG|S_IRWXO);
1192
- FILE *fp;
1193
- int j;
1194
-
1195
- fp = fopen(filename,"w");
1196
- umask(old_umask);
1197
- if (fp == NULL) return -1;
1198
- chmod(filename,S_IRUSR|S_IWUSR);
1199
- for (j = 0; j < history_len; j++)
1200
- fprintf(fp,"%s\n",history[j]);
1201
- fclose(fp);
1202
- return 0;
1203
-}
1204
-
1205
-/* Load the history from the specified file. If the file does not exist
1206
- * zero is returned and no operation is performed.
1207
- *
1208
- * If the file exists and the operation succeeded 0 is returned, otherwise
1209
- * on error -1 is returned. */
1210
-int linenoiseHistoryLoad(const char *filename) {
1211
- FILE *fp = fopen(filename,"r");
1212
- char buf[LINENOISE_MAX_LINE];
1213
-
1214
- if (fp == NULL) return -1;
1215
-
1216
- while (fgets(buf,LINENOISE_MAX_LINE,fp) != NULL) {
1217
- char *p;
1218
-
1219
- p = strchr(buf,'\r');
1220
- if (!p) p = strchr(buf,'\n');
1221
- if (p) *p = '\0';
1222
- linenoiseHistoryAdd(buf);
1223
- }
1224
- fclose(fp);
1225
- return 0;
2706
+ FILE *fp = fopen(filename,"w");
2707
+ int j;
2708
+
2709
+ if (fp == NULL) return -1;
2710
+ for (j = 0; j < history_len; j++) {
2711
+ const char *str = history[j];
2712
+ /* Need to encode backslash, nl and cr */
2713
+ while (*str) {
2714
+ if (*str == '\\') {
2715
+ fputs("\\\\", fp);
2716
+ }
2717
+ else if (*str == '\n') {
2718
+ fputs("\\n", fp);
2719
+ }
2720
+ else if (*str == '\r') {
2721
+ fputs("\\r", fp);
2722
+ }
2723
+ else {
2724
+ fputc(*str, fp);
2725
+ }
2726
+ str++;
2727
+ }
2728
+ fputc('\n', fp);
2729
+ }
2730
+
2731
+ fclose(fp);
2732
+ return 0;
2733
+}
2734
+
2735
+/* Load the history from the specified file.
2736
+ *
2737
+ * If the file does not exist or can't be opened, no operation is performed
2738
+ * and -1 is returned.
2739
+ * Otherwise 0 is returned.
2740
+ */
2741
+int linenoiseHistoryLoad(const char *filename) {
2742
+ FILE *fp = fopen(filename,"r");
2743
+ stringbuf *sb;
2744
+
2745
+ if (fp == NULL) return -1;
2746
+
2747
+ while ((sb = sb_getline(fp)) != NULL) {
2748
+ /* Take the stringbuf and decode backslash escaped values */
2749
+ char *buf = sb_to_string(sb);
2750
+ char *dest = buf;
2751
+ const char *src;
2752
+
2753
+ for (src = buf; *src; src++) {
2754
+ char ch = *src;
2755
+
2756
+ if (ch == '\\') {
2757
+ src++;
2758
+ if (*src == 'n') {
2759
+ ch = '\n';
2760
+ }
2761
+ else if (*src == 'r') {
2762
+ ch = '\r';
2763
+ } else {
2764
+ ch = *src;
2765
+ }
2766
+ }
2767
+ *dest++ = ch;
2768
+ }
2769
+ *dest = 0;
2770
+
2771
+ linenoiseHistoryAddAllocated(buf);
2772
+ }
2773
+ fclose(fp);
2774
+ return 0;
2775
+}
2776
+
2777
+/* Provide access to the history buffer.
2778
+ *
2779
+ * If 'len' is not NULL, the length is stored in *len.
2780
+ */
2781
+char **linenoiseHistory(int *len) {
2782
+ if (len) {
2783
+ *len = history_len;
2784
+ }
2785
+ return history;
12262786
}
12272787
--- extsrc/linenoise.c
+++ extsrc/linenoise.c
@@ -1,19 +1,718 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1 /* linenoise.c -- guerrilla line editing library against the idea that a
2 * line editing lib needs to be 20,000 lines of C code.
3 *
4 * You can find the latest source code at:
5 *
6 * http://github.com/antirez/linenoise
 
7 *
8 * Does a number of crazy assumptions that happen to be true in 99.9999% of
9 * the 2010 UNIX computers around.
10 *
11 * ------------------------------------------------------------------------
12 *
13 * Copyright (c) 2010-2016, Salvatore Sanfilippo <antirez at gmail dot com>
14 * Copyright (c) 2010-2013, Pieter Noordhuis <pcnoordhuis at gmail dot com>
 
15 *
16 * All rights reserved.
17 *
18 * Redistribution and use in source and binary forms, with or without
19 * modification, are permitted provided that the following conditions are
@@ -42,211 +741,381 @@
42 *
43 * References:
44 * - http://invisible-island.net/xterm/ctlseqs/ctlseqs.html
45 * - http://www.3waylabs.com/nw/WWW/products/wizcon/vt220.html
46 *
47 * Todo list:
48 * - Filter bogus Ctrl+<char> combinations.
49 * - Win32 support
50 *
51 * Bloat:
52 * - History search like Ctrl+r in readline?
53 *
 
 
54 * List of escape sequences used by this program, we do everything just
55 * with three sequences. In order to be so cheap we may have some
56 * flickering effect with some slow terminal, but the lesser sequences
57 * the more compatible.
58 *
59 * EL (Erase Line)
60 * Sequence: ESC [ n K
61 * Effect: if n is 0 or missing, clear from cursor to end of line
62 * Effect: if n is 1, clear from beginning of line to cursor
63 * Effect: if n is 2, clear entire line
64 *
65 * CUF (CUrsor Forward)
66 * Sequence: ESC [ n C
67 * Effect: moves cursor forward n chars
68 *
69 * CUB (CUrsor Backward)
70 * Sequence: ESC [ n D
71 * Effect: moves cursor backward n chars
72 *
73 * The following is used to get the terminal width if getting
74 * the width with the TIOCGWINSZ ioctl fails
75 *
76 * DSR (Device Status Report)
77 * Sequence: ESC [ 6 n
78 * Effect: reports the current cusor position as ESC [ n ; m R
79 * where n is the row and m is the column
80 *
81 * When multi line mode is enabled, we also use an additional escape
82 * sequence. However multi line editing is disabled by default.
83 *
84 * CUU (Cursor Up)
85 * Sequence: ESC [ n A
86 * Effect: moves cursor up of n chars.
87 *
88 * CUD (Cursor Down)
89 * Sequence: ESC [ n B
90 * Effect: moves cursor down of n chars.
91 *
92 * When linenoiseClearScreen() is called, two additional escape sequences
93 * are used in order to clear the screen and position the cursor at home
94 * position.
95 *
96 * CUP (Cursor position)
97 * Sequence: ESC [ H
98 * Effect: moves the cursor to upper left corner
99 *
100 * ED (Erase display)
101 * Sequence: ESC [ 2 J
102 * Effect: clear the whole screen
103 *
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
104 */
105
 
 
 
 
 
 
 
 
106 #include <termios.h>
 
 
 
 
 
 
 
107 #include <unistd.h>
 
108 #include <stdlib.h>
 
109 #include <stdio.h>
 
110 #include <errno.h>
111 #include <string.h>
 
112 #include <stdlib.h>
113 #include <ctype.h>
114 #include <sys/stat.h>
115 #include <sys/types.h>
116 #include <sys/ioctl.h>
117 #include <unistd.h>
 
 
 
 
 
118 #include "linenoise.h"
 
 
 
 
 
 
119
120 #define LINENOISE_DEFAULT_HISTORY_MAX_LEN 100
121 #define LINENOISE_MAX_LINE 4096
122 static char *unsupported_term[] = {"dumb","cons25","emacs",NULL};
123 static linenoiseCompletionCallback *completionCallback = NULL;
124 static linenoiseHintsCallback *hintsCallback = NULL;
125 static linenoiseFreeHintsCallback *freeHintsCallback = NULL;
126
127 static struct termios orig_termios; /* In order to restore at exit.*/
128 static int maskmode = 0; /* Show "***" instead of input. For passwords. */
129 static int rawmode = 0; /* For atexit() function to check if restore is needed*/
130 static int mlmode = 0; /* Multi line mode. Default is single line. */
131 static int atexit_registered = 0; /* Register atexit just 1 time. */
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
132 static int history_max_len = LINENOISE_DEFAULT_HISTORY_MAX_LEN;
133 static int history_len = 0;
 
134 static char **history = NULL;
135
136 /* The linenoiseState structure represents the state during line editing.
137 * We pass this state to functions implementing specific editing
138 * functionalities. */
139 struct linenoiseState {
140 int ifd; /* Terminal stdin file descriptor. */
141 int ofd; /* Terminal stdout file descriptor. */
142 char *buf; /* Edited line buffer. */
143 size_t buflen; /* Edited line buffer size. */
144 const char *prompt; /* Prompt to display. */
145 size_t plen; /* Prompt length. */
146 size_t pos; /* Current cursor position. */
147 size_t oldpos; /* Previous refresh cursor position. */
148 size_t len; /* Current edited line length. */
149 size_t cols; /* Number of columns in terminal. */
150 size_t maxrows; /* Maximum num of rows used so far (multiline mode) */
151 int history_index; /* The history index we are currently editing. */
152 };
153
154 enum KEY_ACTION{
155 KEY_NULL = 0, /* NULL */
156 CTRL_A = 1, /* Ctrl+a */
157 CTRL_B = 2, /* Ctrl-b */
158 CTRL_C = 3, /* Ctrl-c */
159 CTRL_D = 4, /* Ctrl-d */
160 CTRL_E = 5, /* Ctrl-e */
161 CTRL_F = 6, /* Ctrl-f */
162 CTRL_H = 8, /* Ctrl-h */
163 TAB = 9, /* Tab */
164 CTRL_K = 11, /* Ctrl+k */
165 CTRL_L = 12, /* Ctrl+l */
166 ENTER = 13, /* Enter */
167 CTRL_N = 14, /* Ctrl-n */
168 CTRL_P = 16, /* Ctrl-p */
169 CTRL_T = 20, /* Ctrl-t */
170 CTRL_U = 21, /* Ctrl+u */
171 CTRL_W = 23, /* Ctrl+w */
172 ESC = 27, /* Escape */
173 BACKSPACE = 127 /* Backspace */
174 };
175
176 static void linenoiseAtExit(void);
177 int linenoiseHistoryAdd(const char *line);
178 static void refreshLine(struct linenoiseState *l);
179
180 /* Debugging macro. */
181 #if 0
182 FILE *lndebug_fp = NULL;
183 #define lndebug(...) \
184 do { \
185 if (lndebug_fp == NULL) { \
186 lndebug_fp = fopen("/tmp/lndebug.txt","a"); \
187 fprintf(lndebug_fp, \
188 "[%d %d %d] p: %d, rows: %d, rpos: %d, max: %d, oldmax: %d\n", \
189 (int)l->len,(int)l->pos,(int)l->oldpos,plen,rows,rpos, \
190 (int)l->maxrows,old_rows); \
191 } \
192 fprintf(lndebug_fp, ", " __VA_ARGS__); \
193 fflush(lndebug_fp); \
194 } while (0)
195 #else
196 #define lndebug(fmt, ...)
197 #endif
198
199 /* ======================= Low level terminal handling ====================== */
200
201 /* Enable "mask mode". When it is enabled, instead of the input that
202 * the user is typing, the terminal will just display a corresponding
203 * number of asterisks, like "****". This is useful for passwords and other
204 * secrets that should not be displayed. */
205 void linenoiseMaskModeEnable(void) {
206 maskmode = 1;
207 }
208
209 /* Disable mask mode. */
210 void linenoiseMaskModeDisable(void) {
211 maskmode = 0;
212 }
213
214 /* Set if to use or not the multi line mode. */
215 void linenoiseSetMultiLine(int ml) {
216 mlmode = ml;
217 }
218
219 /* Return true if the terminal name is in the list of terminals we know are
220 * not able to understand basic escape sequences. */
221 static int isUnsupportedTerm(void) {
222 char *term = getenv("TERM");
223 int j;
224
225 if (term == NULL) return 0;
226 for (j = 0; unsupported_term[j]; j++)
227 if (!strcasecmp(term,unsupported_term[j])) return 1;
228 return 0;
229 }
230
231 /* Raw mode: 1960 magic shit. */
232 static int enableRawMode(int fd) {
233 struct termios raw;
234
235 if (!isatty(STDIN_FILENO)) goto fatal;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
236 if (!atexit_registered) {
237 atexit(linenoiseAtExit);
238 atexit_registered = 1;
239 }
240 if (tcgetattr(fd,&orig_termios) == -1) goto fatal;
241
242 raw = orig_termios; /* modify the original mode */
243 /* input modes: no break, no CR to NL, no parity check, no strip char,
244 * no start/stop output control. */
245 raw.c_iflag &= ~(BRKINT | ICRNL | INPCK | ISTRIP | IXON);
246 /* output modes - disable post processing */
247 raw.c_oflag &= ~(OPOST);
248 /* control modes - set 8 bit chars */
249 raw.c_cflag |= (CS8);
250 /* local modes - choing off, canonical off, no extended functions,
251 * no signal chars (^Z,^C) */
252 raw.c_lflag &= ~(ECHO | ICANON | IEXTEN | ISIG);
@@ -253,163 +1122,452 @@
253 /* control chars - set return condition: min number of bytes and timer.
254 * We want read to return every single byte, without timeout. */
255 raw.c_cc[VMIN] = 1; raw.c_cc[VTIME] = 0; /* 1 byte, no timer */
256
257 /* put terminal in raw mode after flushing */
258 if (tcsetattr(fd,TCSAFLUSH,&raw) < 0) goto fatal;
 
 
259 rawmode = 1;
260 return 0;
261
262 fatal:
263 errno = ENOTTY;
264 return -1;
265 }
266
267 static void disableRawMode(int fd) {
268 /* Don't even check the return value as it's too late. */
269 if (rawmode && tcsetattr(fd,TCSAFLUSH,&orig_termios) != -1)
270 rawmode = 0;
271 }
272
273 /* Use the ESC [6n escape sequence to query the horizontal cursor position
274 * and return it. On error -1 is returned, on success the position of the
275 * cursor. */
276 static int getCursorPosition(int ifd, int ofd) {
277 char buf[32];
278 int cols, rows;
279 unsigned int i = 0;
280
281 /* Report cursor location */
282 if (write(ofd, "\x1b[6n", 4) != 4) return -1;
283
284 /* Read the response: ESC [ rows ; cols R */
285 while (i < sizeof(buf)-1) {
286 if (read(ifd,buf+i,1) != 1) break;
287 if (buf[i] == 'R') break;
288 i++;
289 }
290 buf[i] = '\0';
291
292 /* Parse it. */
293 if (buf[0] != ESC || buf[1] != '[') return -1;
294 if (sscanf(buf+2,"%d;%d",&rows,&cols) != 2) return -1;
295 return cols;
296 }
297
298 /* Try to get the number of columns in the current terminal, or assume 80
299 * if it fails. */
300 static int getColumns(int ifd, int ofd) {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
301 struct winsize ws;
302
303 if (ioctl(1, TIOCGWINSZ, &ws) == -1 || ws.ws_col == 0) {
304 /* ioctl() failed. Try to query the terminal itself. */
305 int start, cols;
306
307 /* Get the initial position so we can restore it later. */
308 start = getCursorPosition(ifd,ofd);
309 if (start == -1) goto failed;
310
311 /* Go to right margin and get position. */
312 if (write(ofd,"\x1b[999C",6) != 6) goto failed;
313 cols = getCursorPosition(ifd,ofd);
314 if (cols == -1) goto failed;
315
316 /* Restore position. */
317 if (cols > start) {
318 char seq[32];
319 snprintf(seq,32,"\x1b[%dD",cols-start);
320 if (write(ofd,seq,strlen(seq)) == -1) {
321 /* Can't recover... */
322 }
323 }
324 return cols;
325 } else {
326 return ws.ws_col;
327 }
328
329 failed:
330 return 80;
331 }
332
333 /* Clear the screen. Used to handle ctrl+l */
334 void linenoiseClearScreen(void) {
335 if (write(STDOUT_FILENO,"\x1b[H\x1b[2J",7) <= 0) {
336 /* nothing to do, just to avoid warning. */
337 }
338 }
339
340 /* Beep, used for completion when there is nothing to complete or when all
341 * the choices were already shown. */
342 static void linenoiseBeep(void) {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
343 fprintf(stderr, "\x7");
344 fflush(stderr);
 
345 }
346
347 /* ============================== Completion ================================ */
348
349 /* Free a list of completion option populated by linenoiseAddCompletion(). */
350 static void freeCompletions(linenoiseCompletions *lc) {
351 size_t i;
352 for (i = 0; i < lc->len; i++)
353 free(lc->cvec[i]);
354 if (lc->cvec != NULL)
355 free(lc->cvec);
356 }
357
358 /* This is an helper function for linenoiseEdit() and is called when the
359 * user types the <tab> key in order to complete the string currently in the
360 * input.
361 *
362 * The state of the editing is encapsulated into the pointed linenoiseState
363 * structure as described in the structure definition. */
364 static int completeLine(struct linenoiseState *ls) {
365 linenoiseCompletions lc = { 0, NULL };
366 int nread, nwritten;
367 char c = 0;
368
369 completionCallback(ls->buf,&lc);
370 if (lc.len == 0) {
371 linenoiseBeep();
372 } else {
373 size_t stop = 0, i = 0;
374
375 while(!stop) {
376 /* Show completion or original buffer */
377 if (i < lc.len) {
378 struct linenoiseState saved = *ls;
379
380 ls->len = ls->pos = strlen(lc.cvec[i]);
381 ls->buf = lc.cvec[i];
382 refreshLine(ls);
383 ls->len = saved.len;
384 ls->pos = saved.pos;
385 ls->buf = saved.buf;
386 } else {
387 refreshLine(ls);
388 }
389
390 nread = read(ls->ifd,&c,1);
391 if (nread <= 0) {
392 freeCompletions(&lc);
393 return -1;
394 }
395
396 switch(c) {
397 case 9: /* tab */
398 i = (i+1) % (lc.len+1);
399 if (i == lc.len) linenoiseBeep();
400 break;
401 case 27: /* escape */
402 /* Re-show original buffer */
403 if (i < lc.len) refreshLine(ls);
 
 
404 stop = 1;
405 break;
406 default:
407 /* Update buffer and return */
408 if (i < lc.len) {
409 nwritten = snprintf(ls->buf,ls->buflen,"%s",lc.cvec[i]);
410 ls->len = ls->pos = nwritten;
411 }
412 stop = 1;
413 break;
414 }
415 }
@@ -417,769 +1575,1126 @@
417
418 freeCompletions(&lc);
419 return c; /* Return last read character */
420 }
421
422 /* Register a callback function to be called for tab-completion. */
423 void linenoiseSetCompletionCallback(linenoiseCompletionCallback *fn) {
 
 
 
424 completionCallback = fn;
425 }
426
427 /* Register a hits function to be called to show hits to the user at the
428 * right of the prompt. */
429 void linenoiseSetHintsCallback(linenoiseHintsCallback *fn) {
430 hintsCallback = fn;
431 }
432
433 /* Register a function to free the hints returned by the hints callback
434 * registered with linenoiseSetHintsCallback(). */
435 void linenoiseSetFreeHintsCallback(linenoiseFreeHintsCallback *fn) {
436 freeHintsCallback = fn;
437 }
438
439 /* This function is used by the callback function registered by the user
440 * in order to add completion options given the input string when the
441 * user typed <tab>. See the example.c source code for a very easy to
442 * understand example. */
443 void linenoiseAddCompletion(linenoiseCompletions *lc, const char *str) {
444 size_t len = strlen(str);
445 char *copy, **cvec;
446
447 copy = malloc(len+1);
448 if (copy == NULL) return;
449 memcpy(copy,str,len+1);
450 cvec = realloc(lc->cvec,sizeof(char*)*(lc->len+1));
451 if (cvec == NULL) {
452 free(copy);
453 return;
454 }
455 lc->cvec = cvec;
456 lc->cvec[lc->len++] = copy;
457 }
458
459 /* =========================== Line editing ================================= */
460
461 /* We define a very simple "append buffer" structure, that is an heap
462 * allocated string where we can append to. This is useful in order to
463 * write all the escape sequences in a buffer and flush them to the standard
464 * output in a single call, to avoid flickering effects. */
465 struct abuf {
466 char *b;
467 int len;
468 };
469
470 static void abInit(struct abuf *ab) {
471 ab->b = NULL;
472 ab->len = 0;
473 }
474
475 static void abAppend(struct abuf *ab, const char *s, int len) {
476 char *new = realloc(ab->b,ab->len+len);
477
478 if (new == NULL) return;
479 memcpy(new+ab->len,s,len);
480 ab->b = new;
481 ab->len += len;
482 }
483
484 static void abFree(struct abuf *ab) {
485 free(ab->b);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
486 }
487
488 /* Helper of refreshSingleLine() and refreshMultiLine() to show hints
489 * to the right of the prompt. */
490 void refreshShowHints(struct abuf *ab, struct linenoiseState *l, int plen) {
491 char seq[64];
492 if (hintsCallback && plen+l->len < l->cols) {
493 int color = -1, bold = 0;
494 char *hint = hintsCallback(l->buf,&color,&bold);
 
 
 
 
 
495 if (hint) {
496 int hintlen = strlen(hint);
497 int hintmaxlen = l->cols-(plen+l->len);
498 if (hintlen > hintmaxlen) hintlen = hintmaxlen;
499 if (bold == 1 && color == -1) color = 37;
500 if (color != -1 || bold != 0)
501 snprintf(seq,64,"\033[%d;%d;49m",bold,color);
502 else
503 seq[0] = '\0';
504 abAppend(ab,seq,strlen(seq));
505 abAppend(ab,hint,hintlen);
506 if (color != -1 || bold != 0)
507 abAppend(ab,"\033[0m",4);
508 /* Call the function to free the hint returned. */
509 if (freeHintsCallback) freeHintsCallback(hint);
510 }
511 }
512 }
513
514 /* Single line low level line refresh.
515 *
516 * Rewrite the currently edited line accordingly to the buffer content,
517 * cursor position, and number of columns of the terminal. */
518 static void refreshSingleLine(struct linenoiseState *l) {
519 char seq[64];
520 size_t plen = strlen(l->prompt);
521 int fd = l->ofd;
522 char *buf = l->buf;
523 size_t len = l->len;
524 size_t pos = l->pos;
525 struct abuf ab;
526
527 while((plen+pos) >= l->cols) {
528 buf++;
529 len--;
530 pos--;
531 }
532 while (plen+len > l->cols) {
533 len--;
534 }
535
536 abInit(&ab);
537 /* Cursor to left edge */
538 snprintf(seq,64,"\r");
539 abAppend(&ab,seq,strlen(seq));
540 /* Write the prompt and the current buffer content */
541 abAppend(&ab,l->prompt,strlen(l->prompt));
542 if (maskmode == 1) {
543 while (len--) abAppend(&ab,"*",1);
544 } else {
545 abAppend(&ab,buf,len);
546 }
547 /* Show hits if any. */
548 refreshShowHints(&ab,l,plen);
549 /* Erase to right */
550 snprintf(seq,64,"\x1b[0K");
551 abAppend(&ab,seq,strlen(seq));
552 /* Move cursor to original position. */
553 snprintf(seq,64,"\r\x1b[%dC", (int)(pos+plen));
554 abAppend(&ab,seq,strlen(seq));
555 if (write(fd,ab.b,ab.len) == -1) {} /* Can't recover from write error. */
556 abFree(&ab);
557 }
558
559 /* Multi line low level line refresh.
560 *
561 * Rewrite the currently edited line accordingly to the buffer content,
562 * cursor position, and number of columns of the terminal. */
563 static void refreshMultiLine(struct linenoiseState *l) {
564 char seq[64];
565 int plen = strlen(l->prompt);
566 int rows = (plen+l->len+l->cols-1)/l->cols; /* rows used by current buf. */
567 int rpos = (plen+l->oldpos+l->cols)/l->cols; /* cursor relative row. */
568 int rpos2; /* rpos after refresh. */
569 int col; /* colum position, zero-based. */
570 int old_rows = l->maxrows;
571 int fd = l->ofd, j;
572 struct abuf ab;
573
574 /* Update maxrows if needed. */
575 if (rows > (int)l->maxrows) l->maxrows = rows;
576
577 /* First step: clear all the lines used before. To do so start by
578 * going to the last row. */
579 abInit(&ab);
580 if (old_rows-rpos > 0) {
581 lndebug("go down %d", old_rows-rpos);
582 snprintf(seq,64,"\x1b[%dB", old_rows-rpos);
583 abAppend(&ab,seq,strlen(seq));
584 }
585
586 /* Now for every row clear it, go up. */
587 for (j = 0; j < old_rows-1; j++) {
588 lndebug("clear+up");
589 snprintf(seq,64,"\r\x1b[0K\x1b[1A");
590 abAppend(&ab,seq,strlen(seq));
591 }
592
593 /* Clean the top line. */
594 lndebug("clear");
595 snprintf(seq,64,"\r\x1b[0K");
596 abAppend(&ab,seq,strlen(seq));
597
598 /* Write the prompt and the current buffer content */
599 abAppend(&ab,l->prompt,strlen(l->prompt));
600 if (maskmode == 1) {
601 unsigned int i;
602 for (i = 0; i < l->len; i++) abAppend(&ab,"*",1);
603 } else {
604 abAppend(&ab,l->buf,l->len);
605 }
606
607 /* Show hits if any. */
608 refreshShowHints(&ab,l,plen);
609
610 /* If we are at the very end of the screen with our prompt, we need to
611 * emit a newline and move the prompt to the first column. */
612 if (l->pos &&
613 l->pos == l->len &&
614 (l->pos+plen) % l->cols == 0)
615 {
616 lndebug("<newline>");
617 abAppend(&ab,"\n",1);
618 snprintf(seq,64,"\r");
619 abAppend(&ab,seq,strlen(seq));
620 rows++;
621 if (rows > (int)l->maxrows) l->maxrows = rows;
622 }
623
624 /* Move cursor to right position. */
625 rpos2 = (plen+l->pos+l->cols)/l->cols; /* current cursor relative row. */
626 lndebug("rpos2 %d", rpos2);
627
628 /* Go up till we reach the expected positon. */
629 if (rows-rpos2 > 0) {
630 lndebug("go-up %d", rows-rpos2);
631 snprintf(seq,64,"\x1b[%dA", rows-rpos2);
632 abAppend(&ab,seq,strlen(seq));
633 }
634
635 /* Set column. */
636 col = (plen+(int)l->pos) % (int)l->cols;
637 lndebug("set col %d", 1+col);
638 if (col)
639 snprintf(seq,64,"\r\x1b[%dC", col);
640 else
641 snprintf(seq,64,"\r");
642 abAppend(&ab,seq,strlen(seq));
643
644 lndebug("\n");
645 l->oldpos = l->pos;
646
647 if (write(fd,ab.b,ab.len) == -1) {} /* Can't recover from write error. */
648 abFree(&ab);
649 }
650
651 /* Calls the two low level functions refreshSingleLine() or
652 * refreshMultiLine() according to the selected mode. */
653 static void refreshLine(struct linenoiseState *l) {
654 if (mlmode)
655 refreshMultiLine(l);
656 else
657 refreshSingleLine(l);
658 }
659
660 /* Insert the character 'c' at cursor current position.
661 *
662 * On error writing to the terminal -1 is returned, otherwise 0. */
663 int linenoiseEditInsert(struct linenoiseState *l, char c) {
664 if (l->len < l->buflen) {
665 if (l->len == l->pos) {
666 l->buf[l->pos] = c;
667 l->pos++;
668 l->len++;
669 l->buf[l->len] = '\0';
670 if ((!mlmode && l->plen+l->len < l->cols && !hintsCallback)) {
671 /* Avoid a full update of the line in the
672 * trivial case. */
673 char d = (maskmode==1) ? '*' : c;
674 if (write(l->ofd,&d,1) == -1) return -1;
675 } else {
676 refreshLine(l);
677 }
678 } else {
679 memmove(l->buf+l->pos+1,l->buf+l->pos,l->len-l->pos);
680 l->buf[l->pos] = c;
681 l->len++;
682 l->pos++;
683 l->buf[l->len] = '\0';
684 refreshLine(l);
685 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
686 }
687 return 0;
688 }
689
690 /* Move cursor on the left. */
691 void linenoiseEditMoveLeft(struct linenoiseState *l) {
692 if (l->pos > 0) {
693 l->pos--;
694 refreshLine(l);
695 }
696 }
697
698 /* Move cursor on the right. */
699 void linenoiseEditMoveRight(struct linenoiseState *l) {
700 if (l->pos != l->len) {
701 l->pos++;
702 refreshLine(l);
703 }
704 }
705
706 /* Move cursor to the start of the line. */
707 void linenoiseEditMoveHome(struct linenoiseState *l) {
708 if (l->pos != 0) {
709 l->pos = 0;
710 refreshLine(l);
711 }
712 }
713
714 /* Move cursor to the end of the line. */
715 void linenoiseEditMoveEnd(struct linenoiseState *l) {
716 if (l->pos != l->len) {
717 l->pos = l->len;
718 refreshLine(l);
719 }
720 }
721
722 /* Substitute the currently edited line with the next or previous history
723 * entry as specified by 'dir'. */
724 #define LINENOISE_HISTORY_NEXT 0
725 #define LINENOISE_HISTORY_PREV 1
726 void linenoiseEditHistoryNext(struct linenoiseState *l, int dir) {
727 if (history_len > 1) {
728 /* Update the current history entry before to
729 * overwrite it with the next one. */
730 free(history[history_len - 1 - l->history_index]);
731 history[history_len - 1 - l->history_index] = strdup(l->buf);
732 /* Show the new entry */
733 l->history_index += (dir == LINENOISE_HISTORY_PREV) ? 1 : -1;
734 if (l->history_index < 0) {
735 l->history_index = 0;
736 return;
737 } else if (l->history_index >= history_len) {
738 l->history_index = history_len-1;
739 return;
740 }
741 strncpy(l->buf,history[history_len - 1 - l->history_index],l->buflen);
742 l->buf[l->buflen-1] = '\0';
743 l->len = l->pos = strlen(l->buf);
744 refreshLine(l);
745 }
746 }
747
748 /* Delete the character at the right of the cursor without altering the cursor
749 * position. Basically this is what happens with the "Delete" keyboard key. */
750 void linenoiseEditDelete(struct linenoiseState *l) {
751 if (l->len > 0 && l->pos < l->len) {
752 memmove(l->buf+l->pos,l->buf+l->pos+1,l->len-l->pos-1);
753 l->len--;
754 l->buf[l->len] = '\0';
755 refreshLine(l);
756 }
757 }
758
759 /* Backspace implementation. */
760 void linenoiseEditBackspace(struct linenoiseState *l) {
761 if (l->pos > 0 && l->len > 0) {
762 memmove(l->buf+l->pos-1,l->buf+l->pos,l->len-l->pos);
763 l->pos--;
764 l->len--;
765 l->buf[l->len] = '\0';
766 refreshLine(l);
767 }
768 }
769
770 /* Delete the previosu word, maintaining the cursor at the start of the
771 * current word. */
772 void linenoiseEditDeletePrevWord(struct linenoiseState *l) {
773 size_t old_pos = l->pos;
774 size_t diff;
775
776 while (l->pos > 0 && l->buf[l->pos-1] == ' ')
777 l->pos--;
778 while (l->pos > 0 && l->buf[l->pos-1] != ' ')
779 l->pos--;
780 diff = old_pos - l->pos;
781 memmove(l->buf+l->pos,l->buf+old_pos,l->len-old_pos+1);
782 l->len -= diff;
783 refreshLine(l);
784 }
785
786 /* This function is the core of the line editing capability of linenoise.
787 * It expects 'fd' to be already in "raw mode" so that every key pressed
788 * will be returned ASAP to read().
789 *
790 * The resulting string is put into 'buf' when the user type enter, or
791 * when ctrl+d is typed.
792 *
793 * The function returns the length of the current buffer. */
794 static int linenoiseEdit(int stdin_fd, int stdout_fd, char *buf, size_t buflen, const char *prompt)
795 {
796 struct linenoiseState l;
797
798 /* Populate the linenoise state that we pass to functions implementing
799 * specific editing functionalities. */
800 l.ifd = stdin_fd;
801 l.ofd = stdout_fd;
802 l.buf = buf;
803 l.buflen = buflen;
804 l.prompt = prompt;
805 l.plen = strlen(prompt);
806 l.oldpos = l.pos = 0;
807 l.len = 0;
808 l.cols = getColumns(stdin_fd, stdout_fd);
809 l.maxrows = 0;
810 l.history_index = 0;
811
812 /* Buffer starts empty. */
813 l.buf[0] = '\0';
814 l.buflen--; /* Make sure there is always space for the nulterm */
815
816 /* The latest history entry is always our current buffer, that
817 * initially is just an empty string. */
818 linenoiseHistoryAdd("");
819
820 if (write(l.ofd,prompt,l.plen) == -1) return -1;
821 while(1) {
822 char c;
823 int nread;
824 char seq[3];
825
826 nread = read(l.ifd,&c,1);
827 if (nread <= 0) return l.len;
828
829 /* Only autocomplete when the callback is set. It returns < 0 when
830 * there was an error reading from fd. Otherwise it will return the
831 * character that should be handled next. */
832 if (c == 9 && completionCallback != NULL) {
833 c = completeLine(&l);
834 /* Return on errors */
835 if (c < 0) return l.len;
836 /* Read next character when 0 */
837 if (c == 0) continue;
838 }
839
840 switch(c) {
841 case ENTER: /* enter */
842 history_len--;
843 free(history[history_len]);
844 if (mlmode) linenoiseEditMoveEnd(&l);
845 if (hintsCallback) {
846 /* Force a refresh without hints to leave the previous
847 * line as the user typed it after a newline. */
848 linenoiseHintsCallback *hc = hintsCallback;
849 hintsCallback = NULL;
850 refreshLine(&l);
851 hintsCallback = hc;
852 }
853 return (int)l.len;
854 case CTRL_C: /* ctrl-c */
855 errno = EAGAIN;
856 return -1;
857 case BACKSPACE: /* backspace */
858 case 8: /* ctrl-h */
859 linenoiseEditBackspace(&l);
860 break;
861 case CTRL_D: /* ctrl-d, remove char at right of cursor, or if the
862 line is empty, act as end-of-file. */
863 if (l.len > 0) {
864 linenoiseEditDelete(&l);
865 } else {
866 history_len--;
867 free(history[history_len]);
868 return -1;
869 }
870 break;
871 case CTRL_T: /* ctrl-t, swaps current character with previous. */
872 if (l.pos > 0 && l.pos < l.len) {
873 int aux = buf[l.pos-1];
874 buf[l.pos-1] = buf[l.pos];
875 buf[l.pos] = aux;
876 if (l.pos != l.len-1) l.pos++;
877 refreshLine(&l);
878 }
879 break;
880 case CTRL_B: /* ctrl-b */
881 linenoiseEditMoveLeft(&l);
882 break;
883 case CTRL_F: /* ctrl-f */
884 linenoiseEditMoveRight(&l);
885 break;
886 case CTRL_P: /* ctrl-p */
887 linenoiseEditHistoryNext(&l, LINENOISE_HISTORY_PREV);
888 break;
889 case CTRL_N: /* ctrl-n */
890 linenoiseEditHistoryNext(&l, LINENOISE_HISTORY_NEXT);
891 break;
892 case ESC: /* escape sequence */
893 /* Read the next two bytes representing the escape sequence.
894 * Use two calls to handle slow terminals returning the two
895 * chars at different times. */
896 if (read(l.ifd,seq,1) == -1) break;
897 if (read(l.ifd,seq+1,1) == -1) break;
898
899 /* ESC [ sequences. */
900 if (seq[0] == '[') {
901 if (seq[1] >= '0' && seq[1] <= '9') {
902 /* Extended escape, read additional byte. */
903 if (read(l.ifd,seq+2,1) == -1) break;
904 if (seq[2] == '~') {
905 switch(seq[1]) {
906 case '3': /* Delete key. */
907 linenoiseEditDelete(&l);
908 break;
909 }
910 }
911 } else {
912 switch(seq[1]) {
913 case 'A': /* Up */
914 linenoiseEditHistoryNext(&l, LINENOISE_HISTORY_PREV);
915 break;
916 case 'B': /* Down */
917 linenoiseEditHistoryNext(&l, LINENOISE_HISTORY_NEXT);
918 break;
919 case 'C': /* Right */
920 linenoiseEditMoveRight(&l);
921 break;
922 case 'D': /* Left */
923 linenoiseEditMoveLeft(&l);
924 break;
925 case 'H': /* Home */
926 linenoiseEditMoveHome(&l);
927 break;
928 case 'F': /* End*/
929 linenoiseEditMoveEnd(&l);
930 break;
931 }
932 }
933 }
934
935 /* ESC O sequences. */
936 else if (seq[0] == 'O') {
937 switch(seq[1]) {
938 case 'H': /* Home */
939 linenoiseEditMoveHome(&l);
940 break;
941 case 'F': /* End*/
942 linenoiseEditMoveEnd(&l);
943 break;
944 }
945 }
946 break;
947 default:
948 if (linenoiseEditInsert(&l,c)) return -1;
949 break;
950 case CTRL_U: /* Ctrl+u, delete the whole line. */
951 buf[0] = '\0';
952 l.pos = l.len = 0;
953 refreshLine(&l);
954 break;
955 case CTRL_K: /* Ctrl+k, delete from current to end of line. */
956 buf[l.pos] = '\0';
957 l.len = l.pos;
958 refreshLine(&l);
959 break;
960 case CTRL_A: /* Ctrl+a, go to the start of the line */
961 linenoiseEditMoveHome(&l);
962 break;
963 case CTRL_E: /* ctrl+e, go to the end of the line */
964 linenoiseEditMoveEnd(&l);
965 break;
966 case CTRL_L: /* ctrl+l, clear screen */
967 linenoiseClearScreen();
968 refreshLine(&l);
969 break;
970 case CTRL_W: /* ctrl+w, delete previous word */
971 linenoiseEditDeletePrevWord(&l);
972 break;
973 }
974 }
975 return l.len;
976 }
977
978 /* This special mode is used by linenoise in order to print scan codes
979 * on screen for debugging / development purposes. It is implemented
980 * by the linenoise_example program using the --keycodes option. */
981 void linenoisePrintKeyCodes(void) {
982 char quit[4];
983
984 printf("Linenoise key codes debugging mode.\n"
985 "Press keys to see scan codes. Type 'quit' at any time to exit.\n");
986 if (enableRawMode(STDIN_FILENO) == -1) return;
987 memset(quit,' ',4);
988 while(1) {
989 char c;
990 int nread;
991
992 nread = read(STDIN_FILENO,&c,1);
993 if (nread <= 0) continue;
994 memmove(quit,quit+1,sizeof(quit)-1); /* shift string to left. */
995 quit[sizeof(quit)-1] = c; /* Insert current char on the right. */
996 if (memcmp(quit,"quit",sizeof(quit)) == 0) break;
997
998 printf("'%c' %02x (%d) (type quit to exit)\n",
999 isprint(c) ? c : '?', (int)c, (int)c);
1000 printf("\r"); /* Go left edge manually, we are in raw mode. */
1001 fflush(stdout);
1002 }
1003 disableRawMode(STDIN_FILENO);
1004 }
1005
1006 /* This function calls the line editing function linenoiseEdit() using
1007 * the STDIN file descriptor set in raw mode. */
1008 static int linenoiseRaw(char *buf, size_t buflen, const char *prompt) {
1009 int count;
1010
1011 if (buflen == 0) {
1012 errno = EINVAL;
1013 return -1;
1014 }
1015
1016 if (enableRawMode(STDIN_FILENO) == -1) return -1;
1017 count = linenoiseEdit(STDIN_FILENO, STDOUT_FILENO, buf, buflen, prompt);
1018 disableRawMode(STDIN_FILENO);
1019 printf("\n");
1020 return count;
1021 }
1022
1023 /* This function is called when linenoise() is called with the standard
1024 * input file descriptor not attached to a TTY. So for example when the
1025 * program using linenoise is called in pipe or with a file redirected
1026 * to its standard input. In this case, we want to be able to return the
1027 * line regardless of its length (by default we are limited to 4k). */
1028 static char *linenoiseNoTTY(void) {
1029 char *line = NULL;
1030 size_t len = 0, maxlen = 0;
1031
1032 while(1) {
1033 int c;
1034 if (len == maxlen) {
1035 char *oldval = line;
1036 if (maxlen == 0) maxlen = 16;
1037 maxlen *= 2;
1038 line = realloc(line,maxlen);
1039 if (line == NULL) {
1040 if (oldval) free(oldval);
1041 return NULL;
1042 }
1043 }
1044 c = fgetc(stdin);
1045 if (c == EOF || c == '\n') {
1046 if (c == EOF && len == 0) {
1047 free(line);
1048 return NULL;
1049 } else {
1050 line[len] = '\0';
1051 return line;
1052 }
1053 } else {
1054 line[len] = c;
1055 len++;
1056 }
1057 }
1058 }
1059
1060 /* The high level function that is the main API of the linenoise library.
1061 * This function checks if the terminal has basic capabilities, just checking
1062 * for a blacklist of stupid terminals, and later either calls the line
1063 * editing function or uses dummy fgets() so that you will be able to type
1064 * something even in the most desperate of the conditions. */
1065 char *linenoise(const char *prompt) {
1066 char buf[LINENOISE_MAX_LINE];
1067 int count;
1068
1069 if (!isatty(STDIN_FILENO)) {
1070 /* Not a tty: read from file / pipe. In this mode we don't want any
1071 * limit to the line size, so we call a function to handle that. */
1072 return linenoiseNoTTY();
1073 } else if (isUnsupportedTerm()) {
1074 size_t len;
1075
1076 printf("%s",prompt);
1077 fflush(stdout);
1078 if (fgets(buf,LINENOISE_MAX_LINE,stdin) == NULL) return NULL;
1079 len = strlen(buf);
1080 while(len && (buf[len-1] == '\n' || buf[len-1] == '\r')) {
1081 len--;
1082 buf[len] = '\0';
1083 }
1084 return strdup(buf);
1085 } else {
1086 count = linenoiseRaw(buf,LINENOISE_MAX_LINE,prompt);
1087 if (count == -1) return NULL;
1088 return strdup(buf);
1089 }
1090 }
1091
1092 /* This is just a wrapper the user may want to call in order to make sure
1093 * the linenoise returned buffer is freed with the same allocator it was
1094 * created with. Useful when the main program is using an alternative
1095 * allocator. */
1096 void linenoiseFree(void *ptr) {
1097 free(ptr);
1098 }
1099
1100 /* ================================ History ================================= */
1101
1102 /* Free the history, but does not reset it. Only used when we have to
1103 * exit() to avoid memory leaks are reported by valgrind & co. */
1104 static void freeHistory(void) {
1105 if (history) {
1106 int j;
1107
1108 for (j = 0; j < history_len; j++)
1109 free(history[j]);
1110 free(history);
1111 }
1112 }
1113
1114 /* At exit we'll try to fix the terminal to the initial conditions. */
1115 static void linenoiseAtExit(void) {
1116 disableRawMode(STDIN_FILENO);
1117 freeHistory();
1118 }
1119
1120 /* This is the API call to add a new entry in the linenoise history.
1121 * It uses a fixed array of char pointers that are shifted (memmoved)
1122 * when the history max length is reached in order to remove the older
1123 * entry and make room for the new one, so it is not exactly suitable for huge
1124 * histories, but will work well for a few hundred of entries.
1125 *
1126 * Using a circular buffer is smarter, but a bit more complex to handle. */
1127 int linenoiseHistoryAdd(const char *line) {
1128 char *linecopy;
1129
1130 if (history_max_len == 0) return 0;
1131
1132 /* Initialization on first call. */
1133 if (history == NULL) {
1134 history = malloc(sizeof(char*)*history_max_len);
1135 if (history == NULL) return 0;
1136 memset(history,0,(sizeof(char*)*history_max_len));
1137 }
1138
1139 /* Don't add duplicated lines. */
1140 if (history_len && !strcmp(history[history_len-1], line)) return 0;
1141
1142 /* Add an heap allocated copy of the line in the history.
1143 * If we reached the max length, remove the older line. */
1144 linecopy = strdup(line);
1145 if (!linecopy) return 0;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1146 if (history_len == history_max_len) {
1147 free(history[0]);
1148 memmove(history,history+1,sizeof(char*)*(history_max_len-1));
1149 history_len--;
1150 }
1151 history[history_len] = linecopy;
1152 history_len++;
1153 return 1;
1154 }
1155
1156 /* Set the maximum length for the history. This function can be called even
1157 * if there is already some history, the function will make sure to retain
1158 * just the latest 'len' elements if the new history length value is smaller
1159 * than the amount of items already inside the history. */
 
 
 
 
1160 int linenoiseHistorySetMaxLen(int len) {
1161 char **new;
1162
1163 if (len < 1) return 0;
1164 if (history) {
1165 int tocopy = history_len;
1166
1167 new = malloc(sizeof(char*)*len);
1168 if (new == NULL) return 0;
1169
1170 /* If we can't copy everything, free the elements we'll not use. */
1171 if (len < tocopy) {
1172 int j;
1173
1174 for (j = 0; j < tocopy-len; j++) free(history[j]);
1175 tocopy = len;
1176 }
1177 memset(new,0,sizeof(char*)*len);
1178 memcpy(new,history+(history_len-tocopy), sizeof(char*)*tocopy);
1179 free(history);
1180 history = new;
1181 }
1182 history_max_len = len;
1183 if (history_len > history_max_len)
1184 history_len = history_max_len;
1185 return 1;
@@ -1186,41 +2701,86 @@
1186 }
1187
1188 /* Save the history in the specified file. On success 0 is returned
1189 * otherwise -1 is returned. */
1190 int linenoiseHistorySave(const char *filename) {
1191 mode_t old_umask = umask(S_IXUSR|S_IRWXG|S_IRWXO);
1192 FILE *fp;
1193 int j;
1194
1195 fp = fopen(filename,"w");
1196 umask(old_umask);
1197 if (fp == NULL) return -1;
1198 chmod(filename,S_IRUSR|S_IWUSR);
1199 for (j = 0; j < history_len; j++)
1200 fprintf(fp,"%s\n",history[j]);
1201 fclose(fp);
1202 return 0;
1203 }
1204
1205 /* Load the history from the specified file. If the file does not exist
1206 * zero is returned and no operation is performed.
1207 *
1208 * If the file exists and the operation succeeded 0 is returned, otherwise
1209 * on error -1 is returned. */
1210 int linenoiseHistoryLoad(const char *filename) {
1211 FILE *fp = fopen(filename,"r");
1212 char buf[LINENOISE_MAX_LINE];
1213
1214 if (fp == NULL) return -1;
1215
1216 while (fgets(buf,LINENOISE_MAX_LINE,fp) != NULL) {
1217 char *p;
1218
1219 p = strchr(buf,'\r');
1220 if (!p) p = strchr(buf,'\n');
1221 if (p) *p = '\0';
1222 linenoiseHistoryAdd(buf);
1223 }
1224 fclose(fp);
1225 return 0;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1226 }
1227
--- extsrc/linenoise.c
+++ extsrc/linenoise.c
@@ -1,19 +1,718 @@
1 #line 1 "utf8.h"
2 #ifndef UTF8_UTIL_H
3 #define UTF8_UTIL_H
4
5 #ifdef __cplusplus
6 extern "C" {
7 #endif
8
9 /**
10 * UTF-8 utility functions
11 *
12 * (c) 2010-2019 Steve Bennett <[email protected]>
13 *
14 * See utf8.c for licence details.
15 */
16
17 #ifndef USE_UTF8
18 #include <ctype.h>
19
20 #define MAX_UTF8_LEN 1
21
22 /* No utf-8 support. 1 byte = 1 char */
23 #define utf8_strlen(S, B) ((B) < 0 ? (int)strlen(S) : (B))
24 #define utf8_strwidth(S, B) utf8_strlen((S), (B))
25 #define utf8_tounicode(S, CP) (*(CP) = (unsigned char)*(S), 1)
26 #define utf8_index(C, I) (I)
27 #define utf8_charlen(C) 1
28 #define utf8_width(C) 1
29
30 #else
31
32 #define MAX_UTF8_LEN 4
33
34 /**
35 * Converts the given unicode codepoint (0 - 0x1fffff) to utf-8
36 * and stores the result at 'p'.
37 *
38 * Returns the number of utf-8 characters
39 */
40 int utf8_fromunicode(char *p, unsigned uc);
41
42 /**
43 * Returns the length of the utf-8 sequence starting with 'c'.
44 *
45 * Returns 1-4, or -1 if this is not a valid start byte.
46 *
47 * Note that charlen=4 is not supported by the rest of the API.
48 */
49 int utf8_charlen(int c);
50
51 /**
52 * Returns the number of characters in the utf-8
53 * string of the given byte length.
54 *
55 * Any bytes which are not part of an valid utf-8
56 * sequence are treated as individual characters.
57 *
58 * The string *must* be null terminated.
59 *
60 * Does not support unicode code points > \u1fffff
61 */
62 int utf8_strlen(const char *str, int bytelen);
63
64 /**
65 * Calculates the display width of the first 'charlen' characters in 'str'.
66 * See utf8_width()
67 */
68 int utf8_strwidth(const char *str, int charlen);
69
70 /**
71 * Returns the byte index of the given character in the utf-8 string.
72 *
73 * The string *must* be null terminated.
74 *
75 * This will return the byte length of a utf-8 string
76 * if given the char length.
77 */
78 int utf8_index(const char *str, int charindex);
79
80 /**
81 * Returns the unicode codepoint corresponding to the
82 * utf-8 sequence 'str'.
83 *
84 * Stores the result in *uc and returns the number of bytes
85 * consumed.
86 *
87 * If 'str' is null terminated, then an invalid utf-8 sequence
88 * at the end of the string will be returned as individual bytes.
89 *
90 * If it is not null terminated, the length *must* be checked first.
91 *
92 * Does not support unicode code points > \u1fffff
93 */
94 int utf8_tounicode(const char *str, int *uc);
95
96 /**
97 * Returns the width (in characters) of the given unicode codepoint.
98 * This is 1 for normal letters and 0 for combining characters and 2 for wide characters.
99 */
100 int utf8_width(int ch);
101
102 #endif
103
104 #ifdef __cplusplus
105 }
106 #endif
107
108 #endif
109 #line 1 "utf8.c"
110 /**
111 * UTF-8 utility functions
112 *
113 * (c) 2010-2019 Steve Bennett <[email protected]>
114 *
115 * All rights reserved.
116 *
117 * Redistribution and use in source and binary forms, with or without
118 * modification, are permitted provided that the following conditions are met:
119 *
120 * * Redistributions of source code must retain the above copyright notice,
121 * this list of conditions and the following disclaimer.
122 *
123 * * Redistributions in binary form must reproduce the above copyright notice,
124 * this list of conditions and the following disclaimer in the documentation
125 * and/or other materials provided with the distribution.
126 *
127 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
128 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
129 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
130 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
131 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
132 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
133 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
134 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
135 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
136 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
137 */
138
139 #include <ctype.h>
140 #include <stdlib.h>
141 #include <string.h>
142 #include <stdio.h>
143 #ifndef UTF8_UTIL_H
144 #include "utf8.h"
145 #endif
146
147 #ifdef USE_UTF8
148 int utf8_fromunicode(char *p, unsigned uc)
149 {
150 if (uc <= 0x7f) {
151 *p = uc;
152 return 1;
153 }
154 else if (uc <= 0x7ff) {
155 *p++ = 0xc0 | ((uc & 0x7c0) >> 6);
156 *p = 0x80 | (uc & 0x3f);
157 return 2;
158 }
159 else if (uc <= 0xffff) {
160 *p++ = 0xe0 | ((uc & 0xf000) >> 12);
161 *p++ = 0x80 | ((uc & 0xfc0) >> 6);
162 *p = 0x80 | (uc & 0x3f);
163 return 3;
164 }
165 /* Note: We silently truncate to 21 bits here: 0x1fffff */
166 else {
167 *p++ = 0xf0 | ((uc & 0x1c0000) >> 18);
168 *p++ = 0x80 | ((uc & 0x3f000) >> 12);
169 *p++ = 0x80 | ((uc & 0xfc0) >> 6);
170 *p = 0x80 | (uc & 0x3f);
171 return 4;
172 }
173 }
174
175 int utf8_charlen(int c)
176 {
177 if ((c & 0x80) == 0) {
178 return 1;
179 }
180 if ((c & 0xe0) == 0xc0) {
181 return 2;
182 }
183 if ((c & 0xf0) == 0xe0) {
184 return 3;
185 }
186 if ((c & 0xf8) == 0xf0) {
187 return 4;
188 }
189 /* Invalid sequence */
190 return -1;
191 }
192
193 int utf8_strlen(const char *str, int bytelen)
194 {
195 int charlen = 0;
196 if (bytelen < 0) {
197 bytelen = strlen(str);
198 }
199 while (bytelen > 0) {
200 int c;
201 int l = utf8_tounicode(str, &c);
202 charlen++;
203 str += l;
204 bytelen -= l;
205 }
206 return charlen;
207 }
208
209 int utf8_strwidth(const char *str, int charlen)
210 {
211 int width = 0;
212 while (charlen) {
213 int c;
214 int l = utf8_tounicode(str, &c);
215 width += utf8_width(c);
216 str += l;
217 charlen--;
218 }
219 return width;
220 }
221
222 int utf8_index(const char *str, int index)
223 {
224 const char *s = str;
225 while (index--) {
226 int c;
227 s += utf8_tounicode(s, &c);
228 }
229 return s - str;
230 }
231
232 int utf8_tounicode(const char *str, int *uc)
233 {
234 unsigned const char *s = (unsigned const char *)str;
235
236 if (s[0] < 0xc0) {
237 *uc = s[0];
238 return 1;
239 }
240 if (s[0] < 0xe0) {
241 if ((s[1] & 0xc0) == 0x80) {
242 *uc = ((s[0] & ~0xc0) << 6) | (s[1] & ~0x80);
243 if (*uc >= 0x80) {
244 return 2;
245 }
246 /* Otherwise this is an invalid sequence */
247 }
248 }
249 else if (s[0] < 0xf0) {
250 if (((str[1] & 0xc0) == 0x80) && ((str[2] & 0xc0) == 0x80)) {
251 *uc = ((s[0] & ~0xe0) << 12) | ((s[1] & ~0x80) << 6) | (s[2] & ~0x80);
252 if (*uc >= 0x800) {
253 return 3;
254 }
255 /* Otherwise this is an invalid sequence */
256 }
257 }
258 else if (s[0] < 0xf8) {
259 if (((str[1] & 0xc0) == 0x80) && ((str[2] & 0xc0) == 0x80) && ((str[3] & 0xc0) == 0x80)) {
260 *uc = ((s[0] & ~0xf0) << 18) | ((s[1] & ~0x80) << 12) | ((s[2] & ~0x80) << 6) | (s[3] & ~0x80);
261 if (*uc >= 0x10000) {
262 return 4;
263 }
264 /* Otherwise this is an invalid sequence */
265 }
266 }
267
268 /* Invalid sequence, so just return the byte */
269 *uc = *s;
270 return 1;
271 }
272
273 struct utf8range {
274 int lower; /* lower inclusive */
275 int upper; /* upper exclusive */
276 };
277
278 /* From http://unicode.org/Public/UNIDATA/UnicodeData.txt */
279 static const struct utf8range unicode_range_combining[] = {
280 { 0x0300, 0x0370 }, { 0x0483, 0x048a }, { 0x0591, 0x05d0 }, { 0x0610, 0x061b },
281 { 0x064b, 0x0660 }, { 0x0670, 0x0671 }, { 0x06d6, 0x06dd }, { 0x06df, 0x06e5 },
282 { 0x06e7, 0x06ee }, { 0x0711, 0x0712 }, { 0x0730, 0x074d }, { 0x07a6, 0x07b1 },
283 { 0x07eb, 0x07f4 }, { 0x0816, 0x0830 }, { 0x0859, 0x085e }, { 0x08d4, 0x0904 },
284 { 0x093a, 0x0958 }, { 0x0962, 0x0964 }, { 0x0981, 0x0985 }, { 0x09bc, 0x09ce },
285 { 0x09d7, 0x09dc }, { 0x09e2, 0x09e6 }, { 0x0a01, 0x0a05 }, { 0x0a3c, 0x0a59 },
286 { 0x0a70, 0x0a72 }, { 0x0a75, 0x0a85 }, { 0x0abc, 0x0ad0 }, { 0x0ae2, 0x0ae6 },
287 { 0x0afa, 0x0b05 }, { 0x0b3c, 0x0b5c }, { 0x0b62, 0x0b66 }, { 0x0b82, 0x0b83 },
288 { 0x0bbe, 0x0bd0 }, { 0x0bd7, 0x0be6 }, { 0x0c00, 0x0c05 }, { 0x0c3e, 0x0c58 },
289 { 0x0c62, 0x0c66 }, { 0x0c81, 0x0c85 }, { 0x0cbc, 0x0cde }, { 0x0ce2, 0x0ce6 },
290 { 0x0d00, 0x0d05 }, { 0x0d3b, 0x0d4e }, { 0x0d57, 0x0d58 }, { 0x0d62, 0x0d66 },
291 { 0x0d82, 0x0d85 }, { 0x0dca, 0x0de6 }, { 0x0df2, 0x0df4 }, { 0x0e31, 0x0e32 },
292 { 0x0e34, 0x0e3f }, { 0x0e47, 0x0e4f }, { 0x0eb1, 0x0eb2 }, { 0x0eb4, 0x0ebd },
293 { 0x0ec8, 0x0ed0 }, { 0x0f18, 0x0f1a }, { 0x0f35, 0x0f3a }, { 0x0f3e, 0x0f40 },
294 { 0x0f71, 0x0f88 }, { 0x0f8d, 0x0fbe }, { 0x0fc6, 0x0fc7 }, { 0x102b, 0x103f },
295 { 0x1056, 0x105a }, { 0x105e, 0x1065 }, { 0x1067, 0x106e }, { 0x1071, 0x1075 },
296 { 0x1082, 0x1090 }, { 0x109a, 0x109e }, { 0x135d, 0x1360 }, { 0x1712, 0x1720 },
297 { 0x1732, 0x1735 }, { 0x1752, 0x1760 }, { 0x1772, 0x1780 }, { 0x17b4, 0x17d4 },
298 { 0x17dd, 0x17e0 }, { 0x180b, 0x180e }, { 0x1885, 0x1887 }, { 0x18a9, 0x18aa },
299 { 0x1920, 0x1940 }, { 0x1a17, 0x1a1e }, { 0x1a55, 0x1a80 }, { 0x1ab0, 0x1b05 },
300 { 0x1b34, 0x1b45 }, { 0x1b6b, 0x1b74 }, { 0x1b80, 0x1b83 }, { 0x1ba1, 0x1bae },
301 { 0x1be6, 0x1bfc }, { 0x1c24, 0x1c3b }, { 0x1cd0, 0x1ce9 }, { 0x1ced, 0x1cee },
302 { 0x1cf2, 0x1cf5 }, { 0x1cf7, 0x1d00 }, { 0x1dc0, 0x1e00 }, { 0x20d0, 0x2100 },
303 { 0x2cef, 0x2cf2 }, { 0x2d7f, 0x2d80 }, { 0x2de0, 0x2e00 }, { 0x302a, 0x3030 },
304 { 0x3099, 0x309b }, { 0xa66f, 0xa67e }, { 0xa69e, 0xa6a0 }, { 0xa6f0, 0xa6f2 },
305 { 0xa802, 0xa803 }, { 0xa806, 0xa807 }, { 0xa80b, 0xa80c }, { 0xa823, 0xa828 },
306 { 0xa880, 0xa882 }, { 0xa8b4, 0xa8ce }, { 0xa8e0, 0xa8f2 }, { 0xa926, 0xa92e },
307 { 0xa947, 0xa95f }, { 0xa980, 0xa984 }, { 0xa9b3, 0xa9c1 }, { 0xa9e5, 0xa9e6 },
308 { 0xaa29, 0xaa40 }, { 0xaa43, 0xaa44 }, { 0xaa4c, 0xaa50 }, { 0xaa7b, 0xaa7e },
309 { 0xaab0, 0xaab5 }, { 0xaab7, 0xaab9 }, { 0xaabe, 0xaac2 }, { 0xaaeb, 0xaaf0 },
310 { 0xaaf5, 0xab01 }, { 0xabe3, 0xabf0 }, { 0xfb1e, 0xfb1f }, { 0xfe00, 0xfe10 },
311 { 0xfe20, 0xfe30 },
312 };
313
314 /* From http://unicode.org/Public/UNIDATA/EastAsianWidth.txt */
315 static const struct utf8range unicode_range_wide[] = {
316 { 0x1100, 0x115f }, { 0x231a, 0x231b }, { 0x2329, 0x232a }, { 0x23e9, 0x23ec },
317 { 0x23f0, 0x23f0 }, { 0x23f3, 0x23f3 }, { 0x25fd, 0x25fe }, { 0x2614, 0x2615 },
318 { 0x2648, 0x2653 }, { 0x267f, 0x267f }, { 0x2693, 0x2693 }, { 0x26a1, 0x26a1 },
319 { 0x26aa, 0x26ab }, { 0x26bd, 0x26be }, { 0x26c4, 0x26c5 }, { 0x26ce, 0x26ce },
320 { 0x26d4, 0x26d4 }, { 0x26ea, 0x26ea }, { 0x26f2, 0x26f3 }, { 0x26f5, 0x26f5 },
321 { 0x26fa, 0x26fa }, { 0x26fd, 0x26fd }, { 0x2705, 0x2705 }, { 0x270a, 0x270b },
322 { 0x2728, 0x2728 }, { 0x274c, 0x274c }, { 0x274e, 0x274e }, { 0x2753, 0x2755 },
323 { 0x2757, 0x2757 }, { 0x2795, 0x2797 }, { 0x27b0, 0x27b0 }, { 0x27bf, 0x27bf },
324 { 0x2b1b, 0x2b1c }, { 0x2b50, 0x2b50 }, { 0x2b55, 0x2b55 }, { 0x2e80, 0x2e99 },
325 { 0x2e9b, 0x2ef3 }, { 0x2f00, 0x2fd5 }, { 0x2ff0, 0x2ffb }, { 0x3001, 0x303e },
326 { 0x3041, 0x3096 }, { 0x3099, 0x30ff }, { 0x3105, 0x312e }, { 0x3131, 0x318e },
327 { 0x3190, 0x31ba }, { 0x31c0, 0x31e3 }, { 0x31f0, 0x321e }, { 0x3220, 0x3247 },
328 { 0x3250, 0x32fe }, { 0x3300, 0x4dbf }, { 0x4e00, 0xa48c }, { 0xa490, 0xa4c6 },
329 { 0xa960, 0xa97c }, { 0xac00, 0xd7a3 }, { 0xf900, 0xfaff }, { 0xfe10, 0xfe19 },
330 { 0xfe30, 0xfe52 }, { 0xfe54, 0xfe66 }, { 0xfe68, 0xfe6b }, { 0x16fe0, 0x16fe1 },
331 { 0x17000, 0x187ec }, { 0x18800, 0x18af2 }, { 0x1b000, 0x1b11e }, { 0x1b170, 0x1b2fb },
332 { 0x1f004, 0x1f004 }, { 0x1f0cf, 0x1f0cf }, { 0x1f18e, 0x1f18e }, { 0x1f191, 0x1f19a },
333 { 0x1f200, 0x1f202 }, { 0x1f210, 0x1f23b }, { 0x1f240, 0x1f248 }, { 0x1f250, 0x1f251 },
334 { 0x1f260, 0x1f265 }, { 0x1f300, 0x1f320 }, { 0x1f32d, 0x1f335 }, { 0x1f337, 0x1f37c },
335 { 0x1f37e, 0x1f393 }, { 0x1f3a0, 0x1f3ca }, { 0x1f3cf, 0x1f3d3 }, { 0x1f3e0, 0x1f3f0 },
336 { 0x1f3f4, 0x1f3f4 }, { 0x1f3f8, 0x1f43e }, { 0x1f440, 0x1f440 }, { 0x1f442, 0x1f4fc },
337 { 0x1f4ff, 0x1f53d }, { 0x1f54b, 0x1f54e }, { 0x1f550, 0x1f567 }, { 0x1f57a, 0x1f57a },
338 { 0x1f595, 0x1f596 }, { 0x1f5a4, 0x1f5a4 }, { 0x1f5fb, 0x1f64f }, { 0x1f680, 0x1f6c5 },
339 { 0x1f6cc, 0x1f6cc }, { 0x1f6d0, 0x1f6d2 }, { 0x1f6eb, 0x1f6ec }, { 0x1f6f4, 0x1f6f8 },
340 { 0x1f910, 0x1f93e }, { 0x1f940, 0x1f94c }, { 0x1f950, 0x1f96b }, { 0x1f980, 0x1f997 },
341 { 0x1f9c0, 0x1f9c0 }, { 0x1f9d0, 0x1f9e6 }, { 0x20000, 0x2fffd }, { 0x30000, 0x3fffd },
342 };
343
344 #define ARRAYSIZE(A) sizeof(A) / sizeof(*(A))
345
346 static int cmp_range(const void *key, const void *cm)
347 {
348 const struct utf8range *range = (const struct utf8range *)cm;
349 int ch = *(int *)key;
350 if (ch < range->lower) {
351 return -1;
352 }
353 if (ch >= range->upper) {
354 return 1;
355 }
356 return 0;
357 }
358
359 static int utf8_in_range(const struct utf8range *range, int num, int ch)
360 {
361 const struct utf8range *r =
362 bsearch(&ch, range, num, sizeof(*range), cmp_range);
363
364 if (r) {
365 return 1;
366 }
367 return 0;
368 }
369
370 int utf8_width(int ch)
371 {
372 /* short circuit for common case */
373 if (isascii(ch)) {
374 return 1;
375 }
376 if (utf8_in_range(unicode_range_combining, ARRAYSIZE(unicode_range_combining), ch)) {
377 return 0;
378 }
379 if (utf8_in_range(unicode_range_wide, ARRAYSIZE(unicode_range_wide), ch)) {
380 return 2;
381 }
382 return 1;
383 }
384 #endif
385 #line 1 "stringbuf.h"
386 #ifndef STRINGBUF_H
387 #define STRINGBUF_H
388 /**
389 * resizable string buffer
390 *
391 * (c) 2017-2020 Steve Bennett <[email protected]>
392 *
393 * See utf8.c for licence details.
394 */
395 #ifdef __cplusplus
396 extern "C" {
397 #endif
398
399 /** @file
400 * A stringbuf is a resizing, null terminated string buffer.
401 *
402 * The buffer is reallocated as necessary.
403 *
404 * In general it is *not* OK to call these functions with a NULL pointer
405 * unless stated otherwise.
406 *
407 * If USE_UTF8 is defined, supports utf8.
408 */
409
410 /**
411 * The stringbuf structure should not be accessed directly.
412 * Use the functions below.
413 */
414 typedef struct {
415 int remaining; /**< Allocated, but unused space */
416 int last; /**< Index of the null terminator (and thus the length of the string) */
417 #ifdef USE_UTF8
418 int chars; /**< Count of characters */
419 #endif
420 char *data; /**< Allocated memory containing the string or NULL for empty */
421 } stringbuf;
422
423 /**
424 * Allocates and returns a new stringbuf with no elements.
425 */
426 stringbuf *sb_alloc(void);
427
428 /**
429 * Frees a stringbuf.
430 * It is OK to call this with NULL.
431 */
432 void sb_free(stringbuf *sb);
433
434 /**
435 * Returns an allocated copy of the stringbuf
436 */
437 stringbuf *sb_copy(stringbuf *sb);
438
439 /**
440 * Returns the byte length of the buffer.
441 *
442 * Returns 0 for both a NULL buffer and an empty buffer.
443 */
444 static inline int sb_len(stringbuf *sb) {
445 return sb->last;
446 }
447
448 /**
449 * Returns the utf8 character length of the buffer.
450 *
451 * Returns 0 for both a NULL buffer and an empty buffer.
452 */
453 static inline int sb_chars(stringbuf *sb) {
454 #ifdef USE_UTF8
455 return sb->chars;
456 #else
457 return sb->last;
458 #endif
459 }
460
461 /**
462 * Appends a null terminated string to the stringbuf
463 */
464 void sb_append(stringbuf *sb, const char *str);
465
466 /**
467 * Like sb_append() except does not require a null terminated string.
468 * The length of 'str' is given as 'len'
469 *
470 * Note that in utf8 mode, characters will *not* be counted correctly
471 * if a partial utf8 sequence is added with sb_append_len()
472 */
473 void sb_append_len(stringbuf *sb, const char *str, int len);
474
475 /**
476 * Returns a pointer to the null terminated string in the buffer.
477 *
478 * Note this pointer only remains valid until the next modification to the
479 * string buffer.
480 *
481 * The returned pointer can be used to update the buffer in-place
482 * as long as care is taken to not overwrite the end of the buffer.
483 */
484 static inline char *sb_str(const stringbuf *sb)
485 {
486 return sb->data;
487 }
488
489 /**
490 * Inserts the given string *before* (zero-based) byte 'index' in the stringbuf.
491 * If index is past the end of the buffer, the string is appended,
492 * just like sb_append()
493 */
494 void sb_insert(stringbuf *sb, int index, const char *str);
495
496 /**
497 * Delete 'len' bytes in the string at the given index.
498 *
499 * Any bytes past the end of the buffer are ignored.
500 * The buffer remains null terminated.
501 *
502 * If len is -1, deletes to the end of the buffer.
503 */
504 void sb_delete(stringbuf *sb, int index, int len);
505
506 /**
507 * Clear to an empty buffer.
508 */
509 void sb_clear(stringbuf *sb);
510
511 /**
512 * Return an allocated copy of buffer and frees 'sb'.
513 *
514 * If 'sb' is empty, returns an allocated copy of "".
515 */
516 char *sb_to_string(stringbuf *sb);
517
518 #ifdef __cplusplus
519 }
520 #endif
521
522 #endif
523 #line 1 "stringbuf.c"
524 /**
525 * resizable string buffer
526 *
527 * (c) 2017-2020 Steve Bennett <[email protected]>
528 *
529 * See utf8.c for licence details.
530 */
531 #include <stdlib.h>
532 #include <string.h>
533 #include <stdio.h>
534 #include <ctype.h>
535 #include <assert.h>
536
537 #ifndef STRINGBUF_H
538 #include "stringbuf.h"
539 #endif
540 #ifdef USE_UTF8
541 #ifndef UTF8_UTIL_H
542 #include "utf8.h"
543 #endif
544 #endif
545
546 #define SB_INCREMENT 200
547
548 stringbuf *sb_alloc(void)
549 {
550 stringbuf *sb = (stringbuf *)malloc(sizeof(*sb));
551 sb->remaining = 0;
552 sb->last = 0;
553 #ifdef USE_UTF8
554 sb->chars = 0;
555 #endif
556 sb->data = NULL;
557
558 return(sb);
559 }
560
561 void sb_free(stringbuf *sb)
562 {
563 if (sb) {
564 free(sb->data);
565 }
566 free(sb);
567 }
568
569 static void sb_realloc(stringbuf *sb, int newlen)
570 {
571 sb->data = (char *)realloc(sb->data, newlen);
572 sb->remaining = newlen - sb->last;
573 }
574
575 void sb_append(stringbuf *sb, const char *str)
576 {
577 sb_append_len(sb, str, strlen(str));
578 }
579
580 void sb_append_len(stringbuf *sb, const char *str, int len)
581 {
582 if (sb->remaining < len + 1) {
583 sb_realloc(sb, sb->last + len + 1 + SB_INCREMENT);
584 }
585 memcpy(sb->data + sb->last, str, len);
586 sb->data[sb->last + len] = 0;
587
588 sb->last += len;
589 sb->remaining -= len;
590 #ifdef USE_UTF8
591 sb->chars += utf8_strlen(str, len);
592 #endif
593 }
594
595 char *sb_to_string(stringbuf *sb)
596 {
597 if (sb->data == NULL) {
598 /* Return an allocated empty string, not null */
599 return strdup("");
600 }
601 else {
602 /* Just return the data and free the stringbuf structure */
603 char *pt = sb->data;
604 free(sb);
605 return pt;
606 }
607 }
608
609 /* Insert and delete operations */
610
611 /* Moves up all the data at position 'pos' and beyond by 'len' bytes
612 * to make room for new data
613 *
614 * Note: Does *not* update sb->chars
615 */
616 static void sb_insert_space(stringbuf *sb, int pos, int len)
617 {
618 assert(pos <= sb->last);
619
620 /* Make sure there is enough space */
621 if (sb->remaining < len) {
622 sb_realloc(sb, sb->last + len + SB_INCREMENT);
623 }
624 /* Now move it up */
625 memmove(sb->data + pos + len, sb->data + pos, sb->last - pos);
626 sb->last += len;
627 sb->remaining -= len;
628 /* And null terminate */
629 sb->data[sb->last] = 0;
630 }
631
632 /**
633 * Move down all the data from pos + len, effectively
634 * deleting the data at position 'pos' of length 'len'
635 */
636 static void sb_delete_space(stringbuf *sb, int pos, int len)
637 {
638 assert(pos < sb->last);
639 assert(pos + len <= sb->last);
640
641 #ifdef USE_UTF8
642 sb->chars -= utf8_strlen(sb->data + pos, len);
643 #endif
644
645 /* Now move it up */
646 memmove(sb->data + pos, sb->data + pos + len, sb->last - pos - len);
647 sb->last -= len;
648 sb->remaining += len;
649 /* And null terminate */
650 sb->data[sb->last] = 0;
651 }
652
653 void sb_insert(stringbuf *sb, int index, const char *str)
654 {
655 if (index >= sb->last) {
656 /* Inserting after the end of the list appends. */
657 sb_append(sb, str);
658 }
659 else {
660 int len = strlen(str);
661
662 sb_insert_space(sb, index, len);
663 memcpy(sb->data + index, str, len);
664 #ifdef USE_UTF8
665 sb->chars += utf8_strlen(str, len);
666 #endif
667 }
668 }
669
670 /**
671 * Delete the bytes at index 'index' for length 'len'
672 * Has no effect if the index is past the end of the list.
673 */
674 void sb_delete(stringbuf *sb, int index, int len)
675 {
676 if (index < sb->last) {
677 char *pos = sb->data + index;
678 if (len < 0) {
679 len = sb->last;
680 }
681
682 sb_delete_space(sb, pos - sb->data, len);
683 }
684 }
685
686 void sb_clear(stringbuf *sb)
687 {
688 if (sb->data) {
689 /* Null terminate */
690 sb->data[0] = 0;
691 sb->last = 0;
692 #ifdef USE_UTF8
693 sb->chars = 0;
694 #endif
695 }
696 }
697 #line 1 "linenoise.c"
698 /* linenoise.c -- guerrilla line editing library against the idea that a
699 * line editing lib needs to be 20,000 lines of C code.
700 *
701 * You can find the latest source code at:
702 *
703 * http://github.com/msteveb/linenoise
704 * (forked from http://github.com/antirez/linenoise)
705 *
706 * Does a number of crazy assumptions that happen to be true in 99.9999% of
707 * the 2010 UNIX computers around.
708 *
709 * ------------------------------------------------------------------------
710 *
711 * Copyright (c) 2010, Salvatore Sanfilippo <antirez at gmail dot com>
712 * Copyright (c) 2010, Pieter Noordhuis <pcnoordhuis at gmail dot com>
713 * Copyright (c) 2011, Steve Bennett <steveb at workware dot net dot au>
714 *
715 * All rights reserved.
716 *
717 * Redistribution and use in source and binary forms, with or without
718 * modification, are permitted provided that the following conditions are
@@ -42,211 +741,381 @@
741 *
742 * References:
743 * - http://invisible-island.net/xterm/ctlseqs/ctlseqs.html
744 * - http://www.3waylabs.com/nw/WWW/products/wizcon/vt220.html
745 *
 
 
 
 
746 * Bloat:
747 * - Completion?
748 *
749 * Unix/termios
750 * ------------
751 * List of escape sequences used by this program, we do everything just
752 * a few sequences. In order to be so cheap we may have some
753 * flickering effect with some slow terminal, but the lesser sequences
754 * the more compatible.
755 *
756 * EL (Erase Line)
757 * Sequence: ESC [ 0 K
758 * Effect: clear from cursor to end of line
 
 
759 *
760 * CUF (CUrsor Forward)
761 * Sequence: ESC [ n C
762 * Effect: moves cursor forward n chars
763 *
764 * CR (Carriage Return)
765 * Sequence: \r
766 * Effect: moves cursor to column 1
767 *
768 * The following are used to clear the screen: ESC [ H ESC [ 2 J
769 * This is actually composed of two sequences:
770 *
771 * cursorhome
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
772 * Sequence: ESC [ H
773 * Effect: moves the cursor to upper left corner
774 *
775 * ED2 (Clear entire screen)
776 * Sequence: ESC [ 2 J
777 * Effect: clear the whole screen
778 *
779 * == For highlighting control characters, we also use the following two ==
780 * SO (enter StandOut)
781 * Sequence: ESC [ 7 m
782 * Effect: Uses some standout mode such as reverse video
783 *
784 * SE (Standout End)
785 * Sequence: ESC [ 0 m
786 * Effect: Exit standout mode
787 *
788 * == Only used if TIOCGWINSZ fails ==
789 * DSR/CPR (Report cursor position)
790 * Sequence: ESC [ 6 n
791 * Effect: reports current cursor position as ESC [ NNN ; MMM R
792 *
793 * == Only used in multiline mode ==
794 * CUU (Cursor Up)
795 * Sequence: ESC [ n A
796 * Effect: moves cursor up n chars.
797 *
798 * CUD (Cursor Down)
799 * Sequence: ESC [ n B
800 * Effect: moves cursor down n chars.
801 *
802 * win32/console
803 * -------------
804 * If __MINGW32__ is defined, the win32 console API is used.
805 * This could probably be made to work for the msvc compiler too.
806 * This support based in part on work by Jon Griffiths.
807 */
808
809 #ifdef _WIN32 /* Windows platform, either MinGW or Visual Studio (MSVC) */
810 #include <windows.h>
811 #include <fcntl.h>
812 #define USE_WINCONSOLE
813 #ifdef __MINGW32__
814 #define HAVE_UNISTD_H
815 #endif
816 #else
817 #include <termios.h>
818 #include <sys/ioctl.h>
819 #include <poll.h>
820 #define USE_TERMIOS
821 #define HAVE_UNISTD_H
822 #endif
823
824 #ifdef HAVE_UNISTD_H
825 #include <unistd.h>
826 #endif
827 #include <stdlib.h>
828 #include <stdarg.h>
829 #include <stdio.h>
830 #include <assert.h>
831 #include <errno.h>
832 #include <string.h>
833 #include <signal.h>
834 #include <stdlib.h>
 
 
835 #include <sys/types.h>
836
837 #if defined(_WIN32) && !defined(__MINGW32__)
838 /* Microsoft headers don't like old POSIX names */
839 #define strdup _strdup
840 #define snprintf _snprintf
841 #endif
842
843 #include "linenoise.h"
844 #ifndef STRINGBUF_H
845 #include "stringbuf.h"
846 #endif
847 #ifndef UTF8_UTIL_H
848 #include "utf8.h"
849 #endif
850
851 #define LINENOISE_DEFAULT_HISTORY_MAX_LEN 100
852
853 /* ctrl('A') -> 0x01 */
854 #define ctrl(C) ((C) - '@')
855 /* meta('a') -> 0xe1 */
856 #define meta(C) ((C) | 0x80)
857
858 /* Use -ve numbers here to co-exist with normal unicode chars */
859 enum {
860 SPECIAL_NONE,
861 /* don't use -1 here since that indicates error */
862 SPECIAL_UP = -20,
863 SPECIAL_DOWN = -21,
864 SPECIAL_LEFT = -22,
865 SPECIAL_RIGHT = -23,
866 SPECIAL_DELETE = -24,
867 SPECIAL_HOME = -25,
868 SPECIAL_END = -26,
869 SPECIAL_INSERT = -27,
870 SPECIAL_PAGE_UP = -28,
871 SPECIAL_PAGE_DOWN = -29,
872
873 /* Some handy names for other special keycodes */
874 CHAR_ESCAPE = 27,
875 CHAR_DELETE = 127,
876 };
877
878 static int history_max_len = LINENOISE_DEFAULT_HISTORY_MAX_LEN;
879 static int history_len = 0;
880 static int history_index = 0;
881 static char **history = NULL;
882
883 /* Structure to contain the status of the current (being edited) line */
884 struct current {
885 stringbuf *buf; /* Current buffer. Always null terminated */
886 int pos; /* Cursor position, measured in chars */
887 int cols; /* Size of the window, in chars */
888 int nrows; /* How many rows are being used in multiline mode (>= 1) */
889 int rpos; /* The current row containing the cursor - multiline mode only */
890 int colsright; /* refreshLine() cached cols for insert_char() optimisation */
891 int colsleft; /* refreshLine() cached cols for remove_char() optimisation */
892 const char *prompt;
893 stringbuf *capture; /* capture buffer, or NULL for none. Always null terminated */
894 stringbuf *output; /* used only during refreshLine() - output accumulator */
895 #if defined(USE_TERMIOS)
896 int fd; /* Terminal fd */
897 #elif defined(USE_WINCONSOLE)
898 HANDLE outh; /* Console output handle */
899 HANDLE inh; /* Console input handle */
900 int rows; /* Screen rows */
901 int x; /* Current column during output */
902 int y; /* Current row */
903 #ifdef USE_UTF8
904 #define UBUF_MAX_CHARS 132
905 WORD ubuf[UBUF_MAX_CHARS + 1]; /* Accumulates utf16 output - one extra for final surrogate pairs */
906 int ubuflen; /* length used in ubuf */
907 int ubufcols; /* how many columns are represented by the chars in ubuf? */
908 #endif
909 #endif
910 };
911
912 static int fd_read(struct current *current);
913 static int getWindowSize(struct current *current);
914 static void cursorDown(struct current *current, int n);
915 static void cursorUp(struct current *current, int n);
916 static void eraseEol(struct current *current);
917 static void refreshLine(struct current *current);
918 static void refreshLineAlt(struct current *current, const char *prompt, const char *buf, int cursor_pos);
919 static void setCursorPos(struct current *current, int x);
920 static void setOutputHighlight(struct current *current, const int *props, int nprops);
921 static void set_current(struct current *current, const char *str);
922
923 static int fd_isatty(struct current *current)
924 {
925 #ifdef USE_TERMIOS
926 return isatty(current->fd);
927 #else
928 (void)current;
929 return 0;
930 #endif
931 }
932
933 void linenoiseHistoryFree(void) {
934 if (history) {
935 int j;
936
937 for (j = 0; j < history_len; j++)
938 free(history[j]);
939 free(history);
940 history = NULL;
941 history_len = 0;
942 }
943 }
944
945 typedef enum {
946 EP_START, /* looking for ESC */
947 EP_ESC, /* looking for [ */
948 EP_DIGITS, /* parsing digits */
949 EP_PROPS, /* parsing digits or semicolons */
950 EP_END, /* ok */
951 EP_ERROR, /* error */
952 } ep_state_t;
953
954 struct esc_parser {
955 ep_state_t state;
956 int props[5]; /* properties are stored here */
957 int maxprops; /* size of the props[] array */
958 int numprops; /* number of properties found */
959 int termchar; /* terminator char, or 0 for any alpha */
960 int current; /* current (partial) property value */
961 };
962
963 /**
964 * Initialise the escape sequence parser at *parser.
965 *
966 * If termchar is 0 any alpha char terminates ok. Otherwise only the given
967 * char terminates successfully.
968 * Run the parser state machine with calls to parseEscapeSequence() for each char.
969 */
970 static void initParseEscapeSeq(struct esc_parser *parser, int termchar)
971 {
972 parser->state = EP_START;
973 parser->maxprops = sizeof(parser->props) / sizeof(*parser->props);
974 parser->numprops = 0;
975 parser->current = 0;
976 parser->termchar = termchar;
977 }
978
979 /**
980 * Pass character 'ch' into the state machine to parse:
981 * 'ESC' '[' <digits> (';' <digits>)* <termchar>
982 *
983 * The first character must be ESC.
984 * Returns the current state. The state machine is done when it returns either EP_END
985 * or EP_ERROR.
986 *
987 * On EP_END, the "property/attribute" values can be read from parser->props[]
988 * of length parser->numprops.
989 */
990 static int parseEscapeSequence(struct esc_parser *parser, int ch)
991 {
992 switch (parser->state) {
993 case EP_START:
994 parser->state = (ch == '\x1b') ? EP_ESC : EP_ERROR;
995 break;
996 case EP_ESC:
997 parser->state = (ch == '[') ? EP_DIGITS : EP_ERROR;
998 break;
999 case EP_PROPS:
1000 if (ch == ';') {
1001 parser->state = EP_DIGITS;
1002 donedigits:
1003 if (parser->numprops + 1 < parser->maxprops) {
1004 parser->props[parser->numprops++] = parser->current;
1005 parser->current = 0;
1006 }
1007 break;
1008 }
1009 /* fall through */
1010 case EP_DIGITS:
1011 if (ch >= '0' && ch <= '9') {
1012 parser->current = parser->current * 10 + (ch - '0');
1013 parser->state = EP_PROPS;
1014 break;
1015 }
1016 /* must be terminator */
1017 if (parser->termchar != ch) {
1018 if (parser->termchar != 0 || !((ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z'))) {
1019 parser->state = EP_ERROR;
1020 break;
1021 }
1022 }
1023 parser->state = EP_END;
1024 goto donedigits;
1025 case EP_END:
1026 parser->state = EP_ERROR;
1027 break;
1028 case EP_ERROR:
1029 break;
1030 }
1031 return parser->state;
1032 }
1033
1034 /*#define DEBUG_REFRESHLINE*/
1035
1036 #ifdef DEBUG_REFRESHLINE
1037 #define DRL(ARGS...) fprintf(dfh, ARGS)
1038 static FILE *dfh;
1039
1040 static void DRL_CHAR(int ch)
1041 {
1042 if (ch < ' ') {
1043 DRL("^%c", ch + '@');
1044 }
1045 else if (ch > 127) {
1046 DRL("\\u%04x", ch);
1047 }
1048 else {
1049 DRL("%c", ch);
1050 }
1051 }
1052 static void DRL_STR(const char *str)
1053 {
1054 while (*str) {
1055 int ch;
1056 int n = utf8_tounicode(str, &ch);
1057 str += n;
1058 DRL_CHAR(ch);
1059 }
1060 }
1061 #else
1062 #define DRL(...)
1063 #define DRL_CHAR(ch)
1064 #define DRL_STR(str)
1065 #endif
1066
1067 #if defined(USE_WINCONSOLE)
1068 #include "linenoise-win32.c"
1069 #endif
1070
1071 #if defined(USE_TERMIOS)
1072 static void linenoiseAtExit(void);
1073 static struct termios orig_termios; /* in order to restore at exit */
1074 static int rawmode = 0; /* for atexit() function to check if restore is needed*/
1075 static int atexit_registered = 0; /* register atexit just 1 time */
1076
1077 static const char *unsupported_term[] = {"dumb","cons25","emacs",NULL};
1078
1079 static int isUnsupportedTerm(void) {
1080 char *term = getenv("TERM");
1081
1082 if (term) {
1083 int j;
1084 for (j = 0; unsupported_term[j]; j++) {
1085 if (strcmp(term, unsupported_term[j]) == 0) {
1086 return 1;
1087 }
1088 }
1089 }
1090 return 0;
1091 }
1092
1093 static int enableRawMode(struct current *current) {
1094 struct termios raw;
1095
1096 current->fd = STDIN_FILENO;
1097 current->cols = 0;
1098
1099 if (!isatty(current->fd) || isUnsupportedTerm() ||
1100 tcgetattr(current->fd, &orig_termios) == -1) {
1101 fatal:
1102 errno = ENOTTY;
1103 return -1;
1104 }
1105
1106 if (!atexit_registered) {
1107 atexit(linenoiseAtExit);
1108 atexit_registered = 1;
1109 }
 
1110
1111 raw = orig_termios; /* modify the original mode */
1112 /* input modes: no break, no CR to NL, no parity check, no strip char,
1113 * no start/stop output control. */
1114 raw.c_iflag &= ~(BRKINT | ICRNL | INPCK | ISTRIP | IXON);
1115 /* output modes - actually, no need to disable post processing */
1116 /*raw.c_oflag &= ~(OPOST);*/
1117 /* control modes - set 8 bit chars */
1118 raw.c_cflag |= (CS8);
1119 /* local modes - choing off, canonical off, no extended functions,
1120 * no signal chars (^Z,^C) */
1121 raw.c_lflag &= ~(ECHO | ICANON | IEXTEN | ISIG);
@@ -253,163 +1122,452 @@
1122 /* control chars - set return condition: min number of bytes and timer.
1123 * We want read to return every single byte, without timeout. */
1124 raw.c_cc[VMIN] = 1; raw.c_cc[VTIME] = 0; /* 1 byte, no timer */
1125
1126 /* put terminal in raw mode after flushing */
1127 if (tcsetattr(current->fd,TCSADRAIN,&raw) < 0) {
1128 goto fatal;
1129 }
1130 rawmode = 1;
1131 return 0;
 
 
 
 
1132 }
1133
1134 static void disableRawMode(struct current *current) {
1135 /* Don't even check the return value as it's too late. */
1136 if (rawmode && tcsetattr(current->fd,TCSADRAIN,&orig_termios) != -1)
1137 rawmode = 0;
1138 }
1139
1140 /* At exit we'll try to fix the terminal to the initial conditions. */
1141 static void linenoiseAtExit(void) {
1142 if (rawmode) {
1143 tcsetattr(STDIN_FILENO, TCSADRAIN, &orig_termios);
1144 }
1145 linenoiseHistoryFree();
1146 }
1147
1148 /* gcc/glibc insists that we care about the return code of write!
1149 * Clarification: This means that a void-cast like "(void) (EXPR)"
1150 * does not work.
1151 */
1152 #define IGNORE_RC(EXPR) if (EXPR) {}
1153
1154 /**
1155 * Output bytes directly, or accumulate output (if current->output is set)
1156 */
1157 static void outputChars(struct current *current, const char *buf, int len)
1158 {
1159 if (len < 0) {
1160 len = strlen(buf);
1161 }
1162 if (current->output) {
1163 sb_append_len(current->output, buf, len);
1164 }
1165 else {
1166 IGNORE_RC(write(current->fd, buf, len));
1167 }
1168 }
1169
1170 /* Like outputChars, but using printf-style formatting
1171 */
1172 static void outputFormatted(struct current *current, const char *format, ...)
1173 {
1174 va_list args;
1175 char buf[64];
1176 int n;
1177
1178 va_start(args, format);
1179 n = vsnprintf(buf, sizeof(buf), format, args);
1180 /* This will never happen because we are sure to use outputFormatted() only for short sequences */
1181 assert(n < (int)sizeof(buf));
1182 va_end(args);
1183 outputChars(current, buf, n);
1184 }
1185
1186 static void cursorToLeft(struct current *current)
1187 {
1188 outputChars(current, "\r", -1);
1189 }
1190
1191 static void setOutputHighlight(struct current *current, const int *props, int nprops)
1192 {
1193 outputChars(current, "\x1b[", -1);
1194 while (nprops--) {
1195 outputFormatted(current, "%d%c", *props, (nprops == 0) ? 'm' : ';');
1196 props++;
1197 }
1198 }
1199
1200 static void eraseEol(struct current *current)
1201 {
1202 outputChars(current, "\x1b[0K", -1);
1203 }
1204
1205 static void setCursorPos(struct current *current, int x)
1206 {
1207 if (x == 0) {
1208 cursorToLeft(current);
1209 }
1210 else {
1211 outputFormatted(current, "\r\x1b[%dC", x);
1212 }
1213 }
1214
1215 static void cursorUp(struct current *current, int n)
1216 {
1217 if (n) {
1218 outputFormatted(current, "\x1b[%dA", n);
1219 }
1220 }
1221
1222 static void cursorDown(struct current *current, int n)
1223 {
1224 if (n) {
1225 outputFormatted(current, "\x1b[%dB", n);
1226 }
1227 }
1228
1229 void linenoiseClearScreen(void)
1230 {
1231 IGNORE_RC(write(STDOUT_FILENO, "\x1b[H\x1b[2J", 7));
1232 }
1233
1234 /**
1235 * Reads a char from 'fd', waiting at most 'timeout' milliseconds.
1236 *
1237 * A timeout of -1 means to wait forever.
1238 *
1239 * Returns -1 if no char is received within the time or an error occurs.
1240 */
1241 static int fd_read_char(int fd, int timeout)
1242 {
1243 struct pollfd p;
1244 unsigned char c;
1245
1246 p.fd = fd;
1247 p.events = POLLIN;
1248
1249 if (poll(&p, 1, timeout) == 0) {
1250 /* timeout */
1251 return -1;
1252 }
1253 if (read(fd, &c, 1) != 1) {
1254 return -1;
1255 }
1256 return c;
1257 }
1258
1259 /**
1260 * Reads a complete utf-8 character
1261 * and returns the unicode value, or -1 on error.
1262 */
1263 static int fd_read(struct current *current)
1264 {
1265 #ifdef USE_UTF8
1266 char buf[MAX_UTF8_LEN];
1267 int n;
1268 int i;
1269 int c;
1270
1271 if (read(current->fd, &buf[0], 1) != 1) {
1272 return -1;
1273 }
1274 n = utf8_charlen(buf[0]);
1275 if (n < 1) {
1276 return -1;
1277 }
1278 for (i = 1; i < n; i++) {
1279 if (read(current->fd, &buf[i], 1) != 1) {
1280 return -1;
1281 }
1282 }
1283 /* decode and return the character */
1284 utf8_tounicode(buf, &c);
1285 return c;
1286 #else
1287 return fd_read_char(current->fd, -1);
1288 #endif
1289 }
1290
1291
1292 /**
1293 * Stores the current cursor column in '*cols'.
1294 * Returns 1 if OK, or 0 if failed to determine cursor pos.
1295 */
1296 static int queryCursor(struct current *current, int* cols)
1297 {
1298 struct esc_parser parser;
1299 int ch;
1300
1301 /* Should not be buffering this output, it needs to go immediately */
1302 assert(current->output == NULL);
1303
1304 /* control sequence - report cursor location */
1305 outputChars(current, "\x1b[6n", -1);
1306
1307 /* Parse the response: ESC [ rows ; cols R */
1308 initParseEscapeSeq(&parser, 'R');
1309 while ((ch = fd_read_char(current->fd, 100)) > 0) {
1310 switch (parseEscapeSequence(&parser, ch)) {
1311 default:
1312 continue;
1313 case EP_END:
1314 if (parser.numprops == 2 && parser.props[1] < 1000) {
1315 *cols = parser.props[1];
1316 return 1;
1317 }
1318 break;
1319 case EP_ERROR:
1320 break;
1321 }
1322 /* failed */
1323 break;
1324 }
1325 return 0;
1326 }
1327
1328 /**
1329 * Updates current->cols with the current window size (width)
1330 */
1331 static int getWindowSize(struct current *current)
1332 {
1333 struct winsize ws;
1334
1335 if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &ws) == 0 && ws.ws_col != 0) {
1336 current->cols = ws.ws_col;
1337 return 0;
1338 }
1339
1340 /* Failed to query the window size. Perhaps we are on a serial terminal.
1341 * Try to query the width by sending the cursor as far to the right
1342 * and reading back the cursor position.
1343 * Note that this is only done once per call to linenoise rather than
1344 * every time the line is refreshed for efficiency reasons.
1345 *
1346 * In more detail, we:
1347 * (a) request current cursor position,
1348 * (b) move cursor far right,
1349 * (c) request cursor position again,
1350 * (d) at last move back to the old position.
1351 * This gives us the width without messing with the externally
1352 * visible cursor position.
1353 */
1354
1355 if (current->cols == 0) {
1356 int here;
1357
1358 /* If anything fails => default 80 */
1359 current->cols = 80;
1360
1361 /* (a) */
1362 if (queryCursor (current, &here)) {
1363 /* (b) */
1364 setCursorPos(current, 999);
1365
1366 /* (c). Note: If (a) succeeded, then (c) should as well.
1367 * For paranoia we still check and have a fallback action
1368 * for (d) in case of failure..
1369 */
1370 if (queryCursor (current, &current->cols)) {
1371 /* (d) Reset the cursor back to the original location. */
1372 if (current->cols > here) {
1373 setCursorPos(current, here);
1374 }
1375 }
1376 }
1377 }
1378
1379 return 0;
1380 }
1381
1382 /**
1383 * If CHAR_ESCAPE was received, reads subsequent
1384 * chars to determine if this is a known special key.
1385 *
1386 * Returns SPECIAL_NONE if unrecognised, or -1 if EOF.
1387 *
1388 * If no additional char is received within a short time,
1389 * CHAR_ESCAPE is returned.
1390 */
1391 static int check_special(int fd)
1392 {
1393 int c = fd_read_char(fd, 50);
1394 int c2;
1395
1396 if (c < 0) {
1397 return CHAR_ESCAPE;
1398 }
1399 else if (c >= 'a' && c <= 'z') {
1400 /* esc-a => meta-a */
1401 return meta(c);
1402 }
1403
1404 c2 = fd_read_char(fd, 50);
1405 if (c2 < 0) {
1406 return c2;
1407 }
1408 if (c == '[' || c == 'O') {
1409 /* Potential arrow key */
1410 switch (c2) {
1411 case 'A':
1412 return SPECIAL_UP;
1413 case 'B':
1414 return SPECIAL_DOWN;
1415 case 'C':
1416 return SPECIAL_RIGHT;
1417 case 'D':
1418 return SPECIAL_LEFT;
1419 case 'F':
1420 return SPECIAL_END;
1421 case 'H':
1422 return SPECIAL_HOME;
1423 }
1424 }
1425 if (c == '[' && c2 >= '1' && c2 <= '8') {
1426 /* extended escape */
1427 c = fd_read_char(fd, 50);
1428 if (c == '~') {
1429 switch (c2) {
1430 case '2':
1431 return SPECIAL_INSERT;
1432 case '3':
1433 return SPECIAL_DELETE;
1434 case '5':
1435 return SPECIAL_PAGE_UP;
1436 case '6':
1437 return SPECIAL_PAGE_DOWN;
1438 case '7':
1439 return SPECIAL_HOME;
1440 case '8':
1441 return SPECIAL_END;
1442 }
1443 }
1444 while (c != -1 && c != '~') {
1445 /* .e.g \e[12~ or '\e[11;2~ discard the complete sequence */
1446 c = fd_read_char(fd, 50);
1447 }
1448 }
1449
1450 return SPECIAL_NONE;
1451 }
1452 #endif
1453
1454 static void clearOutputHighlight(struct current *current)
1455 {
1456 int nohighlight = 0;
1457 setOutputHighlight(current, &nohighlight, 1);
1458 }
1459
1460 static void outputControlChar(struct current *current, char ch)
1461 {
1462 int reverse = 7;
1463 setOutputHighlight(current, &reverse, 1);
1464 outputChars(current, "^", 1);
1465 outputChars(current, &ch, 1);
1466 clearOutputHighlight(current);
1467 }
1468
1469 #ifndef utf8_getchars
1470 static int utf8_getchars(char *buf, int c)
1471 {
1472 #ifdef USE_UTF8
1473 return utf8_fromunicode(buf, c);
1474 #else
1475 *buf = c;
1476 return 1;
1477 #endif
1478 }
1479 #endif
1480
1481 /**
1482 * Returns the unicode character at the given offset,
1483 * or -1 if none.
1484 */
1485 static int get_char(struct current *current, int pos)
1486 {
1487 if (pos >= 0 && pos < sb_chars(current->buf)) {
1488 int c;
1489 int i = utf8_index(sb_str(current->buf), pos);
1490 (void)utf8_tounicode(sb_str(current->buf) + i, &c);
1491 return c;
1492 }
1493 return -1;
1494 }
1495
1496 static int char_display_width(int ch)
1497 {
1498 if (ch < ' ') {
1499 /* control chars take two positions */
1500 return 2;
1501 }
1502 else {
1503 return utf8_width(ch);
1504 }
1505 }
1506
1507 #ifndef NO_COMPLETION
1508 static linenoiseCompletionCallback *completionCallback = NULL;
1509 static void *completionUserdata = NULL;
1510 static int showhints = 1;
1511 static linenoiseHintsCallback *hintsCallback = NULL;
1512 static linenoiseFreeHintsCallback *freeHintsCallback = NULL;
1513 static void *hintsUserdata = NULL;
1514
1515 static void beep(void) {
1516 #ifdef USE_TERMIOS
1517 fprintf(stderr, "\x7");
1518 fflush(stderr);
1519 #endif
1520 }
1521
 
 
 
1522 static void freeCompletions(linenoiseCompletions *lc) {
1523 size_t i;
1524 for (i = 0; i < lc->len; i++)
1525 free(lc->cvec[i]);
1526 free(lc->cvec);
 
1527 }
1528
1529 static int completeLine(struct current *current) {
 
 
 
 
 
 
1530 linenoiseCompletions lc = { 0, NULL };
1531 int c = 0;
 
1532
1533 completionCallback(sb_str(current->buf),&lc,completionUserdata);
1534 if (lc.len == 0) {
1535 beep();
1536 } else {
1537 size_t stop = 0, i = 0;
1538
1539 while(!stop) {
1540 /* Show completion or original buffer */
1541 if (i < lc.len) {
1542 int chars = utf8_strlen(lc.cvec[i], -1);
1543 refreshLineAlt(current, current->prompt, lc.cvec[i], chars);
 
 
 
 
 
 
1544 } else {
1545 refreshLine(current);
1546 }
1547
1548 c = fd_read(current);
1549 if (c == -1) {
1550 break;
 
1551 }
1552
1553 switch(c) {
1554 case '\t': /* tab */
1555 i = (i+1) % (lc.len+1);
1556 if (i == lc.len) beep();
1557 break;
1558 case CHAR_ESCAPE: /* escape */
1559 /* Re-show original buffer */
1560 if (i < lc.len) {
1561 refreshLine(current);
1562 }
1563 stop = 1;
1564 break;
1565 default:
1566 /* Update buffer and return */
1567 if (i < lc.len) {
1568 set_current(current,lc.cvec[i]);
 
1569 }
1570 stop = 1;
1571 break;
1572 }
1573 }
@@ -417,769 +1575,1126 @@
1575
1576 freeCompletions(&lc);
1577 return c; /* Return last read character */
1578 }
1579
1580 /* Register a callback function to be called for tab-completion.
1581 Returns the prior callback so that the caller may (if needed)
1582 restore it when done. */
1583 linenoiseCompletionCallback * linenoiseSetCompletionCallback(linenoiseCompletionCallback *fn, void *userdata) {
1584 linenoiseCompletionCallback * old = completionCallback;
1585 completionCallback = fn;
1586 completionUserdata = userdata;
1587 return old;
1588 }
1589
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1590 void linenoiseAddCompletion(linenoiseCompletions *lc, const char *str) {
1591 lc->cvec = (char **)realloc(lc->cvec,sizeof(char*)*(lc->len+1));
1592 lc->cvec[lc->len++] = strdup(str);
1593 }
1594
1595 void linenoiseSetHintsCallback(linenoiseHintsCallback *callback, void *userdata)
1596 {
1597 hintsCallback = callback;
1598 hintsUserdata = userdata;
1599 }
1600
1601 void linenoiseSetFreeHintsCallback(linenoiseFreeHintsCallback *callback)
1602 {
1603 freeHintsCallback = callback;
1604 }
1605
1606 #endif
1607
1608
1609 static const char *reduceSingleBuf(const char *buf, int availcols, int *cursor_pos)
1610 {
1611 /* We have availcols columns available.
1612 * If necessary, strip chars off the front of buf until *cursor_pos
1613 * fits within availcols
1614 */
1615 int needcols = 0;
1616 int pos = 0;
1617 int new_cursor_pos = *cursor_pos;
1618 const char *pt = buf;
1619
1620 DRL("reduceSingleBuf: availcols=%d, cursor_pos=%d\n", availcols, *cursor_pos);
1621
1622 while (*pt) {
1623 int ch;
1624 int n = utf8_tounicode(pt, &ch);
1625 pt += n;
1626
1627 needcols += char_display_width(ch);
1628
1629 /* If we need too many cols, strip
1630 * chars off the front of buf to make it fit.
1631 * We keep 3 extra cols to the right of the cursor.
1632 * 2 for possible wide chars, 1 for the last column that
1633 * can't be used.
1634 */
1635 while (needcols >= availcols - 3) {
1636 n = utf8_tounicode(buf, &ch);
1637 buf += n;
1638 needcols -= char_display_width(ch);
1639 DRL_CHAR(ch);
1640
1641 /* and adjust the apparent cursor position */
1642 new_cursor_pos--;
1643
1644 if (buf == pt) {
1645 /* can't remove more than this */
1646 break;
1647 }
1648 }
1649
1650 if (pos++ == *cursor_pos) {
1651 break;
1652 }
1653
1654 }
1655 DRL("<snip>");
1656 DRL_STR(buf);
1657 DRL("\nafter reduce, needcols=%d, new_cursor_pos=%d\n", needcols, new_cursor_pos);
1658
1659 /* Done, now new_cursor_pos contains the adjusted cursor position
1660 * and buf points to he adjusted start
1661 */
1662 *cursor_pos = new_cursor_pos;
1663 return buf;
1664 }
1665
1666 static int mlmode = 0;
1667
1668 void linenoiseSetMultiLine(int enableml)
1669 {
1670 mlmode = enableml;
1671 }
1672
1673 /* Helper of refreshSingleLine() and refreshMultiLine() to show hints
1674 * to the right of the prompt.
1675 * Returns 1 if a hint was shown, or 0 if not
1676 * If 'display' is 0, does no output. Just returns the appropriate return code.
1677 */
1678 static int refreshShowHints(struct current *current, const char *buf, int availcols, int display)
1679 {
1680 int rc = 0;
1681 if (showhints && hintsCallback && availcols > 0) {
1682 int bold = 0;
1683 int color = -1;
1684 char *hint = hintsCallback(buf, &color, &bold, hintsUserdata);
1685 if (hint) {
1686 rc = 1;
1687 if (display) {
1688 const char *pt;
1689 if (bold == 1 && color == -1) color = 37;
1690 if (bold || color > 0) {
1691 int props[3] = { bold, color, 49 }; /* bold, color, fgnormal */
1692 setOutputHighlight(current, props, 3);
1693 }
1694 DRL("<hint bold=%d,color=%d>", bold, color);
1695 pt = hint;
1696 while (*pt) {
1697 int ch;
1698 int n = utf8_tounicode(pt, &ch);
1699 int width = char_display_width(ch);
1700
1701 if (width >= availcols) {
1702 DRL("<hinteol>");
1703 break;
1704 }
1705 DRL_CHAR(ch);
1706
1707 availcols -= width;
1708 outputChars(current, pt, n);
1709 pt += n;
1710 }
1711 if (bold || color > 0) {
1712 clearOutputHighlight(current);
1713 }
1714 /* Call the function to free the hint returned. */
1715 if (freeHintsCallback) freeHintsCallback(hint, hintsUserdata);
1716 }
1717 }
1718 }
1719 return rc;
1720 }
1721
1722 #ifdef USE_TERMIOS
1723 static void refreshStart(struct current *current)
1724 {
1725 /* We accumulate all output here */
1726 assert(current->output == NULL);
1727 current->output = sb_alloc();
1728 }
1729
1730 static void refreshEnd(struct current *current)
1731 {
1732 /* Output everything at once */
1733 IGNORE_RC(write(current->fd, sb_str(current->output), sb_len(current->output)));
1734 sb_free(current->output);
1735 current->output = NULL;
1736 }
1737
1738 static void refreshStartChars(struct current *current)
1739 {
1740 (void)current;
1741 }
1742
1743 static void refreshNewline(struct current *current)
1744 {
1745 DRL("<nl>");
1746 outputChars(current, "\n", 1);
1747 }
1748
1749 static void refreshEndChars(struct current *current)
1750 {
1751 (void)current;
1752 }
1753 #endif
1754
1755 static void refreshLineAlt(struct current *current, const char *prompt, const char *buf, int cursor_pos)
1756 {
1757 int i;
1758 const char *pt;
1759 int displaycol;
1760 int displayrow;
1761 int visible;
1762 int currentpos;
1763 int notecursor;
1764 int cursorcol = 0;
1765 int cursorrow = 0;
1766 int hint;
1767 struct esc_parser parser;
1768
1769 #ifdef DEBUG_REFRESHLINE
1770 dfh = fopen("linenoise.debuglog", "a");
1771 #endif
1772
1773 /* Should intercept SIGWINCH. For now, just get the size every time */
1774 getWindowSize(current);
1775
1776 refreshStart(current);
1777
1778 DRL("wincols=%d, cursor_pos=%d, nrows=%d, rpos=%d\n", current->cols, cursor_pos, current->nrows, current->rpos);
1779
1780 /* Here is the plan:
1781 * (a) move the the bottom row, going down the appropriate number of lines
1782 * (b) move to beginning of line and erase the current line
1783 * (c) go up one line and do the same, until we have erased up to the first row
1784 * (d) output the prompt, counting cols and rows, taking into account escape sequences
1785 * (e) output the buffer, counting cols and rows
1786 * (e') when we hit the current pos, save the cursor position
1787 * (f) move the cursor to the saved cursor position
1788 * (g) save the current cursor row and number of rows
1789 */
1790
1791 /* (a) - The cursor is currently at row rpos */
1792 cursorDown(current, current->nrows - current->rpos - 1);
1793 DRL("<cud=%d>", current->nrows - current->rpos - 1);
1794
1795 /* (b), (c) - Erase lines upwards until we get to the first row */
1796 for (i = 0; i < current->nrows; i++) {
1797 if (i) {
1798 DRL("<cup>");
1799 cursorUp(current, 1);
1800 }
1801 DRL("<clearline>");
1802 cursorToLeft(current);
1803 eraseEol(current);
1804 }
1805 DRL("\n");
1806
1807 /* (d) First output the prompt. control sequences don't take up display space */
1808 pt = prompt;
1809 displaycol = 0; /* current display column */
1810 displayrow = 0; /* current display row */
1811 visible = 1;
1812
1813 refreshStartChars(current);
1814
1815 while (*pt) {
1816 int width;
1817 int ch;
1818 int n = utf8_tounicode(pt, &ch);
1819
1820 if (visible && ch == CHAR_ESCAPE) {
1821 /* The start of an escape sequence, so not visible */
1822 visible = 0;
1823 initParseEscapeSeq(&parser, 'm');
1824 DRL("<esc-seq-start>");
1825 }
1826
1827 if (ch == '\n' || ch == '\r') {
1828 /* treat both CR and NL the same and force wrap */
1829 refreshNewline(current);
1830 displaycol = 0;
1831 displayrow++;
1832 }
1833 else {
1834 width = visible * utf8_width(ch);
1835
1836 displaycol += width;
1837 if (displaycol >= current->cols) {
1838 /* need to wrap to the next line because of newline or if it doesn't fit
1839 * XXX this is a problem in single line mode
1840 */
1841 refreshNewline(current);
1842 displaycol = width;
1843 displayrow++;
1844 }
1845
1846 DRL_CHAR(ch);
1847 #ifdef USE_WINCONSOLE
1848 if (visible) {
1849 outputChars(current, pt, n);
1850 }
1851 #else
1852 outputChars(current, pt, n);
1853 #endif
1854 }
1855 pt += n;
1856
1857 if (!visible) {
1858 switch (parseEscapeSequence(&parser, ch)) {
1859 case EP_END:
1860 visible = 1;
1861 setOutputHighlight(current, parser.props, parser.numprops);
1862 DRL("<esc-seq-end,numprops=%d>", parser.numprops);
1863 break;
1864 case EP_ERROR:
1865 DRL("<esc-seq-err>");
1866 visible = 1;
1867 break;
1868 }
1869 }
1870 }
1871
1872 /* Now we are at the first line with all lines erased */
1873 DRL("\nafter prompt: displaycol=%d, displayrow=%d\n", displaycol, displayrow);
1874
1875
1876 /* (e) output the buffer, counting cols and rows */
1877 if (mlmode == 0) {
1878 /* In this mode we may need to trim chars from the start of the buffer until the
1879 * cursor fits in the window.
1880 */
1881 pt = reduceSingleBuf(buf, current->cols - displaycol, &cursor_pos);
1882 }
1883 else {
1884 pt = buf;
1885 }
1886
1887 currentpos = 0;
1888 notecursor = -1;
1889
1890 while (*pt) {
1891 int ch;
1892 int n = utf8_tounicode(pt, &ch);
1893 int width = char_display_width(ch);
1894
1895 if (currentpos == cursor_pos) {
1896 /* (e') wherever we output this character is where we want the cursor */
1897 notecursor = 1;
1898 }
1899
1900 if (displaycol + width >= current->cols) {
1901 if (mlmode == 0) {
1902 /* In single line mode stop once we print as much as we can on one line */
1903 DRL("<slmode>");
1904 break;
1905 }
1906 /* need to wrap to the next line since it doesn't fit */
1907 refreshNewline(current);
1908 displaycol = 0;
1909 displayrow++;
1910 }
1911
1912 if (notecursor == 1) {
1913 /* (e') Save this position as the current cursor position */
1914 cursorcol = displaycol;
1915 cursorrow = displayrow;
1916 notecursor = 0;
1917 DRL("<cursor>");
1918 }
1919
1920 displaycol += width;
1921
1922 if (ch < ' ') {
1923 outputControlChar(current, ch + '@');
1924 }
1925 else {
1926 outputChars(current, pt, n);
1927 }
1928 DRL_CHAR(ch);
1929 if (width != 1) {
1930 DRL("<w=%d>", width);
1931 }
1932
1933 pt += n;
1934 currentpos++;
1935 }
1936
1937 /* If we didn't see the cursor, it is at the current location */
1938 if (notecursor) {
1939 DRL("<cursor>");
1940 cursorcol = displaycol;
1941 cursorrow = displayrow;
1942 }
1943
1944 DRL("\nafter buf: displaycol=%d, displayrow=%d, cursorcol=%d, cursorrow=%d\n", displaycol, displayrow, cursorcol, cursorrow);
1945
1946 /* (f) show hints */
1947 hint = refreshShowHints(current, buf, current->cols - displaycol, 1);
1948
1949 /* Remember how many many cols are available for insert optimisation */
1950 if (prompt == current->prompt && hint == 0) {
1951 current->colsright = current->cols - displaycol;
1952 current->colsleft = displaycol;
1953 }
1954 else {
1955 /* Can't optimise */
1956 current->colsright = 0;
1957 current->colsleft = 0;
1958 }
1959 DRL("\nafter hints: colsleft=%d, colsright=%d\n\n", current->colsleft, current->colsright);
1960
1961 refreshEndChars(current);
1962
1963 /* (g) move the cursor to the correct place */
1964 cursorUp(current, displayrow - cursorrow);
1965 setCursorPos(current, cursorcol);
1966
1967 /* (h) Update the number of rows if larger, but never reduce this */
1968 if (displayrow >= current->nrows) {
1969 current->nrows = displayrow + 1;
1970 }
1971 /* And remember the row that the cursor is on */
1972 current->rpos = cursorrow;
1973
1974 refreshEnd(current);
1975
1976 #ifdef DEBUG_REFRESHLINE
1977 fclose(dfh);
1978 #endif
1979 }
1980
1981 static void refreshLine(struct current *current)
1982 {
1983 refreshLineAlt(current, current->prompt, sb_str(current->buf), current->pos);
1984 }
1985
1986 static void set_current(struct current *current, const char *str)
1987 {
1988 sb_clear(current->buf);
1989 sb_append(current->buf, str);
1990 current->pos = sb_chars(current->buf);
1991 }
1992
1993 /**
1994 * Removes the char at 'pos'.
1995 *
1996 * Returns 1 if the line needs to be refreshed, 2 if not
1997 * and 0 if nothing was removed
1998 */
1999 static int remove_char(struct current *current, int pos)
2000 {
2001 if (pos >= 0 && pos < sb_chars(current->buf)) {
2002 int offset = utf8_index(sb_str(current->buf), pos);
2003 int nbytes = utf8_index(sb_str(current->buf) + offset, 1);
2004 int rc = 1;
2005
2006 /* Now we try to optimise in the simple but very common case that:
2007 * - outputChars() can be used directly (not win32)
2008 * - we are removing the char at EOL
2009 * - the buffer is not empty
2010 * - there are columns available to the left
2011 * - the char being deleted is not a wide or utf-8 character
2012 * - no hints are being shown
2013 */
2014 if (current->output && current->pos == pos + 1 && current->pos == sb_chars(current->buf) && pos > 0) {
2015 #ifdef USE_UTF8
2016 /* Could implement utf8_prev_len() but simplest just to not optimise this case */
2017 char last = sb_str(current->buf)[offset];
2018 #else
2019 char last = 0;
2020 #endif
2021 if (current->colsleft > 0 && (last & 0x80) == 0) {
2022 /* Have cols on the left and not a UTF-8 char or continuation */
2023 /* Yes, can optimise */
2024 current->colsleft--;
2025 current->colsright++;
2026 rc = 2;
2027 }
2028 }
2029
2030 sb_delete(current->buf, offset, nbytes);
2031
2032 if (current->pos > pos) {
2033 current->pos--;
2034 }
2035 if (rc == 2) {
2036 if (refreshShowHints(current, sb_str(current->buf), current->colsright, 0)) {
2037 /* A hint needs to be shown, so can't optimise after all */
2038 rc = 1;
2039 }
2040 else {
2041 /* optimised output */
2042 outputChars(current, "\b \b", 3);
2043 }
2044 }
2045 return rc;
2046 return 1;
2047 }
2048 return 0;
2049 }
2050
2051 /**
2052 * Insert 'ch' at position 'pos'
2053 *
2054 * Returns 1 if the line needs to be refreshed, 2 if not
2055 * and 0 if nothing was inserted (no room)
2056 */
2057 static int insert_char(struct current *current, int pos, int ch)
2058 {
2059 if (pos >= 0 && pos <= sb_chars(current->buf)) {
2060 char buf[MAX_UTF8_LEN + 1];
2061 int offset = utf8_index(sb_str(current->buf), pos);
2062 int n = utf8_getchars(buf, ch);
2063 int rc = 1;
2064
2065 /* null terminate since sb_insert() requires it */
2066 buf[n] = 0;
2067
2068 /* Now we try to optimise in the simple but very common case that:
2069 * - outputChars() can be used directly (not win32)
2070 * - we are inserting at EOL
2071 * - there are enough columns available
2072 * - no hints are being shown
2073 */
2074 if (current->output && pos == current->pos && pos == sb_chars(current->buf)) {
2075 int width = char_display_width(ch);
2076 if (current->colsright > width) {
2077 /* Yes, can optimise */
2078 current->colsright -= width;
2079 current->colsleft -= width;
2080 rc = 2;
2081 }
2082 }
2083 sb_insert(current->buf, offset, buf);
2084 if (current->pos >= pos) {
2085 current->pos++;
2086 }
2087 if (rc == 2) {
2088 if (refreshShowHints(current, sb_str(current->buf), current->colsright, 0)) {
2089 /* A hint needs to be shown, so can't optimise after all */
2090 rc = 1;
2091 }
2092 else {
2093 /* optimised output */
2094 outputChars(current, buf, n);
2095 }
2096 }
2097 return rc;
2098 }
2099 return 0;
2100 }
2101
2102 /**
2103 * Captures up to 'n' characters starting at 'pos' for the cut buffer.
2104 *
2105 * This replaces any existing characters in the cut buffer.
2106 */
2107 static void capture_chars(struct current *current, int pos, int nchars)
2108 {
2109 if (pos >= 0 && (pos + nchars - 1) < sb_chars(current->buf)) {
2110 int offset = utf8_index(sb_str(current->buf), pos);
2111 int nbytes = utf8_index(sb_str(current->buf) + offset, nchars);
2112
2113 if (nbytes > 0) {
2114 if (current->capture) {
2115 sb_clear(current->capture);
2116 }
2117 else {
2118 current->capture = sb_alloc();
2119 }
2120 sb_append_len(current->capture, sb_str(current->buf) + offset, nbytes);
2121 }
2122 }
2123 }
2124
2125 /**
2126 * Removes up to 'n' characters at cursor position 'pos'.
2127 *
2128 * Returns 0 if no chars were removed or non-zero otherwise.
2129 */
2130 static int remove_chars(struct current *current, int pos, int n)
2131 {
2132 int removed = 0;
2133
2134 /* First save any chars which will be removed */
2135 capture_chars(current, pos, n);
2136
2137 while (n-- && remove_char(current, pos)) {
2138 removed++;
2139 }
2140 return removed;
2141 }
2142 /**
2143 * Inserts the characters (string) 'chars' at the cursor position 'pos'.
2144 *
2145 * Returns 0 if no chars were inserted or non-zero otherwise.
2146 */
2147 static int insert_chars(struct current *current, int pos, const char *chars)
2148 {
2149 int inserted = 0;
2150
2151 while (*chars) {
2152 int ch;
2153 int n = utf8_tounicode(chars, &ch);
2154 if (insert_char(current, pos, ch) == 0) {
2155 break;
2156 }
2157 inserted++;
2158 pos++;
2159 chars += n;
2160 }
2161 return inserted;
2162 }
2163
2164 static int skip_space_nonspace(struct current *current, int dir, int check_is_space)
2165 {
2166 int moved = 0;
2167 int checkoffset = (dir < 0) ? -1 : 0;
2168 int limit = (dir < 0) ? 0 : sb_chars(current->buf);
2169 while (current->pos != limit && (get_char(current, current->pos + checkoffset) == ' ') == check_is_space) {
2170 current->pos += dir;
2171 moved++;
2172 }
2173 return moved;
2174 }
2175
2176 static int skip_space(struct current *current, int dir)
2177 {
2178 return skip_space_nonspace(current, dir, 1);
2179 }
2180
2181 static int skip_nonspace(struct current *current, int dir)
2182 {
2183 return skip_space_nonspace(current, dir, 0);
2184 }
2185
2186 static void set_history_index(struct current *current, int new_index)
2187 {
2188 if (history_len > 1) {
2189 /* Update the current history entry before to
2190 * overwrite it with the next one. */
2191 free(history[history_len - 1 - history_index]);
2192 history[history_len - 1 - history_index] = strdup(sb_str(current->buf));
2193 /* Show the new entry */
2194 history_index = new_index;
2195 if (history_index < 0) {
2196 history_index = 0;
2197 } else if (history_index >= history_len) {
2198 history_index = history_len - 1;
2199 } else {
2200 set_current(current, history[history_len - 1 - history_index]);
2201 refreshLine(current);
2202 }
2203 }
2204 }
2205
2206 /**
2207 * Returns the keycode to process, or 0 if none.
2208 */
2209 static int reverseIncrementalSearch(struct current *current)
2210 {
2211 /* Display the reverse-i-search prompt and process chars */
2212 char rbuf[50];
2213 char rprompt[80];
2214 int rchars = 0;
2215 int rlen = 0;
2216 int searchpos = history_len - 1;
2217 int c;
2218
2219 rbuf[0] = 0;
2220 while (1) {
2221 int n = 0;
2222 const char *p = NULL;
2223 int skipsame = 0;
2224 int searchdir = -1;
2225
2226 snprintf(rprompt, sizeof(rprompt), "(reverse-i-search)'%s': ", rbuf);
2227 refreshLineAlt(current, rprompt, sb_str(current->buf), current->pos);
2228 c = fd_read(current);
2229 if (c == ctrl('H') || c == CHAR_DELETE) {
2230 if (rchars) {
2231 int p_ind = utf8_index(rbuf, --rchars);
2232 rbuf[p_ind] = 0;
2233 rlen = strlen(rbuf);
2234 }
2235 continue;
2236 }
2237 #ifdef USE_TERMIOS
2238 if (c == CHAR_ESCAPE) {
2239 c = check_special(current->fd);
2240 }
2241 #endif
2242 if (c == ctrl('R')) {
2243 /* Search for the previous (earlier) match */
2244 if (searchpos > 0) {
2245 searchpos--;
2246 }
2247 skipsame = 1;
2248 }
2249 else if (c == ctrl('S')) {
2250 /* Search for the next (later) match */
2251 if (searchpos < history_len) {
2252 searchpos++;
2253 }
2254 searchdir = 1;
2255 skipsame = 1;
2256 }
2257 else if (c == ctrl('P') || c == SPECIAL_UP) {
2258 /* Exit Ctrl-R mode and go to the previous history line from the current search pos */
2259 set_history_index(current, history_len - searchpos);
2260 c = 0;
2261 break;
2262 }
2263 else if (c == ctrl('N') || c == SPECIAL_DOWN) {
2264 /* Exit Ctrl-R mode and go to the next history line from the current search pos */
2265 set_history_index(current, history_len - searchpos - 2);
2266 c = 0;
2267 break;
2268 }
2269 else if (c >= ' ' && c <= '~') {
2270 /* >= here to allow for null terminator */
2271 if (rlen >= (int)sizeof(rbuf) - MAX_UTF8_LEN) {
2272 continue;
2273 }
2274
2275 n = utf8_getchars(rbuf + rlen, c);
2276 rlen += n;
2277 rchars++;
2278 rbuf[rlen] = 0;
2279
2280 /* Adding a new char resets the search location */
2281 searchpos = history_len - 1;
2282 }
2283 else {
2284 /* Exit from incremental search mode */
2285 break;
2286 }
2287
2288 /* Now search through the history for a match */
2289 for (; searchpos >= 0 && searchpos < history_len; searchpos += searchdir) {
2290 p = strstr(history[searchpos], rbuf);
2291 if (p) {
2292 /* Found a match */
2293 if (skipsame && strcmp(history[searchpos], sb_str(current->buf)) == 0) {
2294 /* But it is identical, so skip it */
2295 continue;
2296 }
2297 /* Copy the matching line and set the cursor position */
2298 history_index = history_len - 1 - searchpos;
2299 set_current(current,history[searchpos]);
2300 current->pos = utf8_strlen(history[searchpos], p - history[searchpos]);
2301 break;
2302 }
2303 }
2304 if (!p && n) {
2305 /* No match, so don't add it */
2306 rchars--;
2307 rlen -= n;
2308 rbuf[rlen] = 0;
2309 }
2310 }
2311 if (c == ctrl('G') || c == ctrl('C')) {
2312 /* ctrl-g terminates the search with no effect */
2313 set_current(current, "");
2314 history_index = 0;
2315 c = 0;
2316 }
2317 else if (c == ctrl('J')) {
2318 /* ctrl-j terminates the search leaving the buffer in place */
2319 history_index = 0;
2320 c = 0;
2321 }
2322 /* Go process the char normally */
2323 refreshLine(current);
2324 return c;
2325 }
2326
2327 static int linenoiseEdit(struct current *current) {
2328 history_index = 0;
2329
2330 refreshLine(current);
2331
2332 while(1) {
2333 int c = fd_read(current);
2334
2335 #ifndef NO_COMPLETION
2336 /* Only autocomplete when the callback is set. It returns < 0 when
2337 * there was an error reading from fd. Otherwise it will return the
2338 * character that should be handled next. */
2339 if (c == '\t' && current->pos == sb_chars(current->buf) && completionCallback != NULL) {
2340 c = completeLine(current);
2341 }
2342 #endif
2343 if (c == ctrl('R')) {
2344 /* reverse incremental search will provide an alternative keycode or 0 for none */
2345 c = reverseIncrementalSearch(current);
2346 /* go on to process the returned char normally */
2347 }
2348
2349 #ifdef USE_TERMIOS
2350 if (c == CHAR_ESCAPE) { /* escape sequence */
2351 c = check_special(current->fd);
2352 }
2353 #endif
2354 if (c == -1) {
2355 /* Return on errors */
2356 return sb_len(current->buf);
2357 }
2358
2359 switch(c) {
2360 case SPECIAL_NONE:
2361 break;
2362 case '\r': /* enter/CR */
2363 case '\n': /* LF */
2364 history_len--;
2365 free(history[history_len]);
2366 current->pos = sb_chars(current->buf);
2367 if (mlmode || hintsCallback) {
2368 showhints = 0;
2369 refreshLine(current);
2370 showhints = 1;
2371 }
2372 return sb_len(current->buf);
2373 case ctrl('C'): /* ctrl-c */
2374 errno = EAGAIN;
2375 return -1;
2376 case ctrl('Z'): /* ctrl-z */
2377 #ifdef SIGTSTP
2378 /* send ourselves SIGSUSP */
2379 disableRawMode(current);
2380 raise(SIGTSTP);
2381 /* and resume */
2382 enableRawMode(current);
2383 refreshLine(current);
2384 #endif
2385 continue;
2386 case CHAR_DELETE: /* backspace */
2387 case ctrl('H'):
2388 if (remove_char(current, current->pos - 1) == 1) {
2389 refreshLine(current);
2390 }
2391 break;
2392 case ctrl('D'): /* ctrl-d */
2393 if (sb_len(current->buf) == 0) {
2394 /* Empty line, so EOF */
2395 history_len--;
2396 free(history[history_len]);
2397 return -1;
2398 }
2399 /* Otherwise fall through to delete char to right of cursor */
2400 /* fall-thru */
2401 case SPECIAL_DELETE:
2402 if (remove_char(current, current->pos) == 1) {
2403 refreshLine(current);
2404 }
2405 break;
2406 case SPECIAL_INSERT:
2407 /* Ignore. Expansion Hook.
2408 * Future possibility: Toggle Insert/Overwrite Modes
2409 */
2410 break;
2411 case meta('b'): /* meta-b, move word left */
2412 if (skip_nonspace(current, -1)) {
2413 refreshLine(current);
2414 }
2415 else if (skip_space(current, -1)) {
2416 skip_nonspace(current, -1);
2417 refreshLine(current);
2418 }
2419 break;
2420 case meta('f'): /* meta-f, move word right */
2421 if (skip_space(current, 1)) {
2422 refreshLine(current);
2423 }
2424 else if (skip_nonspace(current, 1)) {
2425 skip_space(current, 1);
2426 refreshLine(current);
2427 }
2428 break;
2429 case ctrl('W'): /* ctrl-w, delete word at left. save deleted chars */
2430 /* eat any spaces on the left */
2431 {
2432 int pos = current->pos;
2433 while (pos > 0 && get_char(current, pos - 1) == ' ') {
2434 pos--;
2435 }
2436
2437 /* now eat any non-spaces on the left */
2438 while (pos > 0 && get_char(current, pos - 1) != ' ') {
2439 pos--;
2440 }
2441
2442 if (remove_chars(current, pos, current->pos - pos)) {
2443 refreshLine(current);
2444 }
2445 }
2446 break;
2447 case ctrl('T'): /* ctrl-t */
2448 if (current->pos > 0 && current->pos <= sb_chars(current->buf)) {
2449 /* If cursor is at end, transpose the previous two chars */
2450 int fixer = (current->pos == sb_chars(current->buf));
2451 c = get_char(current, current->pos - fixer);
2452 remove_char(current, current->pos - fixer);
2453 insert_char(current, current->pos - 1, c);
2454 refreshLine(current);
2455 }
2456 break;
2457 case ctrl('V'): /* ctrl-v */
2458 /* Insert the ^V first */
2459 if (insert_char(current, current->pos, c)) {
2460 refreshLine(current);
2461 /* Now wait for the next char. Can insert anything except \0 */
2462 c = fd_read(current);
2463
2464 /* Remove the ^V first */
2465 remove_char(current, current->pos - 1);
2466 if (c > 0) {
2467 /* Insert the actual char, can't be error or null */
2468 insert_char(current, current->pos, c);
2469 }
2470 refreshLine(current);
2471 }
2472 break;
2473 case ctrl('B'):
2474 case SPECIAL_LEFT:
2475 if (current->pos > 0) {
2476 current->pos--;
2477 refreshLine(current);
2478 }
2479 break;
2480 case ctrl('F'):
2481 case SPECIAL_RIGHT:
2482 if (current->pos < sb_chars(current->buf)) {
2483 current->pos++;
2484 refreshLine(current);
2485 }
2486 break;
2487 case SPECIAL_PAGE_UP: /* move to start of history */
2488 set_history_index(current, history_len - 1);
2489 break;
2490 case SPECIAL_PAGE_DOWN: /* move to 0 == end of history, i.e. current */
2491 set_history_index(current, 0);
2492 break;
2493 case ctrl('P'):
2494 case SPECIAL_UP:
2495 set_history_index(current, history_index + 1);
2496 break;
2497 case ctrl('N'):
2498 case SPECIAL_DOWN:
2499 set_history_index(current, history_index - 1);
2500 break;
2501 case ctrl('A'): /* Ctrl+a, go to the start of the line */
2502 case SPECIAL_HOME:
2503 current->pos = 0;
2504 refreshLine(current);
2505 break;
2506 case ctrl('E'): /* ctrl+e, go to the end of the line */
2507 case SPECIAL_END:
2508 current->pos = sb_chars(current->buf);
2509 refreshLine(current);
2510 break;
2511 case ctrl('U'): /* Ctrl+u, delete to beginning of line, save deleted chars. */
2512 if (remove_chars(current, 0, current->pos)) {
2513 refreshLine(current);
2514 }
2515 break;
2516 case ctrl('K'): /* Ctrl+k, delete from current to end of line, save deleted chars. */
2517 if (remove_chars(current, current->pos, sb_chars(current->buf) - current->pos)) {
2518 refreshLine(current);
2519 }
2520 break;
2521 case ctrl('Y'): /* Ctrl+y, insert saved chars at current position */
2522 if (current->capture && insert_chars(current, current->pos, sb_str(current->capture))) {
2523 refreshLine(current);
2524 }
2525 break;
2526 case ctrl('L'): /* Ctrl+L, clear screen */
2527 linenoiseClearScreen();
2528 /* Force recalc of window size for serial terminals */
2529 current->cols = 0;
2530 current->rpos = 0;
2531 refreshLine(current);
2532 break;
2533 default:
2534 if (c >= meta('a') && c <= meta('z')) {
2535 /* Don't insert meta chars that are not bound */
2536 break;
2537 }
2538 /* Only tab is allowed without ^V */
2539 if (c == '\t' || c >= ' ') {
2540 if (insert_char(current, current->pos, c) == 1) {
2541 refreshLine(current);
2542 }
2543 }
2544 break;
2545 }
2546 }
2547 return sb_len(current->buf);
2548 }
2549
2550 int linenoiseColumns(void)
2551 {
2552 struct current current;
2553 current.output = NULL;
2554 enableRawMode (&current);
2555 getWindowSize (&current);
2556 disableRawMode (&current);
2557 return current.cols;
2558 }
2559
2560 /**
2561 * Reads a line from the file handle (without the trailing NL or CRNL)
2562 * and returns it in a stringbuf.
2563 * Returns NULL if no characters are read before EOF or error.
2564 *
2565 * Note that the character count will *not* be correct for lines containing
2566 * utf8 sequences. Do not rely on the character count.
2567 */
2568 static stringbuf *sb_getline(FILE *fh)
2569 {
2570 stringbuf *sb = sb_alloc();
2571 int c;
2572 int n = 0;
2573
2574 while ((c = getc(fh)) != EOF) {
2575 char ch;
2576 n++;
2577 if (c == '\r') {
2578 /* CRLF -> LF */
2579 continue;
2580 }
2581 if (c == '\n' || c == '\r') {
2582 break;
2583 }
2584 ch = c;
2585 /* ignore the effect of character count for partial utf8 sequences */
2586 sb_append_len(sb, &ch, 1);
2587 }
2588 if (n == 0 || sb->data == NULL) {
2589 sb_free(sb);
2590 return NULL;
2591 }
2592 return sb;
2593 }
2594
2595 char *linenoiseWithInitial(const char *prompt, const char *initial)
2596 {
2597 int count;
2598 struct current current;
2599 stringbuf *sb;
2600
2601 memset(&current, 0, sizeof(current));
2602
2603 if (enableRawMode(&current) == -1) {
2604 printf("%s", prompt);
2605 fflush(stdout);
2606 sb = sb_getline(stdin);
2607 if (sb && !fd_isatty(&current)) {
2608 printf("%s\n", sb_str(sb));
2609 fflush(stdout);
2610 }
2611 }
2612 else {
2613 current.buf = sb_alloc();
2614 current.pos = 0;
2615 current.nrows = 1;
2616 current.prompt = prompt;
2617
2618 /* The latest history entry is always our current buffer */
2619 linenoiseHistoryAdd(initial);
2620 set_current(&current, initial);
2621
2622 count = linenoiseEdit(&current);
2623
2624 disableRawMode(&current);
2625 printf("\n");
2626
2627 sb_free(current.capture);
2628 if (count == -1) {
2629 sb_free(current.buf);
2630 return NULL;
2631 }
2632 sb = current.buf;
2633 }
2634 return sb ? sb_to_string(sb) : NULL;
2635 }
2636
2637 char *linenoise(const char *prompt)
2638 {
2639 return linenoiseWithInitial(prompt, "");
2640 }
2641
2642 /* Using a circular buffer is smarter, but a bit more complex to handle. */
2643 static int linenoiseHistoryAddAllocated(char *line) {
2644
2645 if (history_max_len == 0) {
2646 notinserted:
2647 free(line);
2648 return 0;
2649 }
2650 if (history == NULL) {
2651 history = (char **)calloc(sizeof(char*), history_max_len);
2652 }
2653
2654 /* do not insert duplicate lines into history */
2655 if (history_len > 0 && strcmp(line, history[history_len - 1]) == 0) {
2656 goto notinserted;
2657 }
2658
2659 if (history_len == history_max_len) {
2660 free(history[0]);
2661 memmove(history,history+1,sizeof(char*)*(history_max_len-1));
2662 history_len--;
2663 }
2664 history[history_len] = line;
2665 history_len++;
2666 return 1;
2667 }
2668
2669 int linenoiseHistoryAdd(const char *line) {
2670 return linenoiseHistoryAddAllocated(strdup(line));
2671 }
2672
2673 int linenoiseHistoryGetMaxLen(void) {
2674 return history_max_len;
2675 }
2676
2677 int linenoiseHistorySetMaxLen(int len) {
2678 char **newHistory;
2679
2680 if (len < 1) return 0;
2681 if (history) {
2682 int tocopy = history_len;
2683
2684 newHistory = (char **)calloc(sizeof(char*), len);
 
2685
2686 /* If we can't copy everything, free the elements we'll not use. */
2687 if (len < tocopy) {
2688 int j;
2689
2690 for (j = 0; j < tocopy-len; j++) free(history[j]);
2691 tocopy = len;
2692 }
2693 memcpy(newHistory,history+(history_len-tocopy), sizeof(char*)*tocopy);
 
2694 free(history);
2695 history = newHistory;
2696 }
2697 history_max_len = len;
2698 if (history_len > history_max_len)
2699 history_len = history_max_len;
2700 return 1;
@@ -1186,41 +2701,86 @@
2701 }
2702
2703 /* Save the history in the specified file. On success 0 is returned
2704 * otherwise -1 is returned. */
2705 int linenoiseHistorySave(const char *filename) {
2706 FILE *fp = fopen(filename,"w");
2707 int j;
2708
2709 if (fp == NULL) return -1;
2710 for (j = 0; j < history_len; j++) {
2711 const char *str = history[j];
2712 /* Need to encode backslash, nl and cr */
2713 while (*str) {
2714 if (*str == '\\') {
2715 fputs("\\\\", fp);
2716 }
2717 else if (*str == '\n') {
2718 fputs("\\n", fp);
2719 }
2720 else if (*str == '\r') {
2721 fputs("\\r", fp);
2722 }
2723 else {
2724 fputc(*str, fp);
2725 }
2726 str++;
2727 }
2728 fputc('\n', fp);
2729 }
2730
2731 fclose(fp);
2732 return 0;
2733 }
2734
2735 /* Load the history from the specified file.
2736 *
2737 * If the file does not exist or can't be opened, no operation is performed
2738 * and -1 is returned.
2739 * Otherwise 0 is returned.
2740 */
2741 int linenoiseHistoryLoad(const char *filename) {
2742 FILE *fp = fopen(filename,"r");
2743 stringbuf *sb;
2744
2745 if (fp == NULL) return -1;
2746
2747 while ((sb = sb_getline(fp)) != NULL) {
2748 /* Take the stringbuf and decode backslash escaped values */
2749 char *buf = sb_to_string(sb);
2750 char *dest = buf;
2751 const char *src;
2752
2753 for (src = buf; *src; src++) {
2754 char ch = *src;
2755
2756 if (ch == '\\') {
2757 src++;
2758 if (*src == 'n') {
2759 ch = '\n';
2760 }
2761 else if (*src == 'r') {
2762 ch = '\r';
2763 } else {
2764 ch = *src;
2765 }
2766 }
2767 *dest++ = ch;
2768 }
2769 *dest = 0;
2770
2771 linenoiseHistoryAddAllocated(buf);
2772 }
2773 fclose(fp);
2774 return 0;
2775 }
2776
2777 /* Provide access to the history buffer.
2778 *
2779 * If 'len' is not NULL, the length is stored in *len.
2780 */
2781 char **linenoiseHistory(int *len) {
2782 if (len) {
2783 *len = history_len;
2784 }
2785 return history;
2786 }
2787
+97 -23
--- extsrc/linenoise.h
+++ extsrc/linenoise.h
@@ -1,16 +1,14 @@
1
-/* linenoise.h -- VERSION 1.0
2
- *
3
- * Guerrilla line editing library against the idea that a line editing lib
4
- * needs to be 20,000 lines of C code.
1
+/* linenoise.h -- guerrilla line editing library against the idea that a
2
+ * line editing lib needs to be 20,000 lines of C code.
53
*
64
* See linenoise.c for more information.
75
*
86
* ------------------------------------------------------------------------
97
*
10
- * Copyright (c) 2010-2014, Salvatore Sanfilippo <antirez at gmail dot com>
11
- * Copyright (c) 2010-2013, Pieter Noordhuis <pcnoordhuis at gmail dot com>
8
+ * Copyright (c) 2010, Salvatore Sanfilippo <antirez at gmail dot com>
9
+ * Copyright (c) 2010, Pieter Noordhuis <pcnoordhuis at gmail dot com>
1210
*
1311
* All rights reserved.
1412
*
1513
* Redistribution and use in source and binary forms, with or without
1614
* modification, are permitted provided that the following conditions are
@@ -41,35 +39,111 @@
4139
4240
#ifdef __cplusplus
4341
extern "C" {
4442
#endif
4543
44
+#ifndef NO_COMPLETION
4645
typedef struct linenoiseCompletions {
4746
size_t len;
4847
char **cvec;
4948
} linenoiseCompletions;
5049
51
-typedef void(linenoiseCompletionCallback)(const char *, linenoiseCompletions *);
52
-typedef char*(linenoiseHintsCallback)(const char *, int *color, int *bold);
53
-typedef void(linenoiseFreeHintsCallback)(void *);
54
-void linenoiseSetCompletionCallback(linenoiseCompletionCallback *);
55
-void linenoiseSetHintsCallback(linenoiseHintsCallback *);
56
-void linenoiseSetFreeHintsCallback(linenoiseFreeHintsCallback *);
57
-void linenoiseAddCompletion(linenoiseCompletions *, const char *);
58
-
50
+/*
51
+ * The callback type for tab completion handlers.
52
+ */
53
+typedef void(linenoiseCompletionCallback)(const char *prefix, linenoiseCompletions *comp, void *userdata);
54
+
55
+/*
56
+ * Sets the current tab completion handler and returns the previous one, or NULL
57
+ * if no prior one has been set.
58
+ */
59
+linenoiseCompletionCallback * linenoiseSetCompletionCallback(linenoiseCompletionCallback *comp, void *userdata);
60
+
61
+/*
62
+ * Adds a copy of the given string to the given completion list. The copy is owned
63
+ * by the linenoiseCompletions object.
64
+ */
65
+void linenoiseAddCompletion(linenoiseCompletions *comp, const char *str);
66
+
67
+typedef char*(linenoiseHintsCallback)(const char *, int *color, int *bold, void *userdata);
68
+typedef void(linenoiseFreeHintsCallback)(void *hint, void *userdata);
69
+void linenoiseSetHintsCallback(linenoiseHintsCallback *callback, void *userdata);
70
+void linenoiseSetFreeHintsCallback(linenoiseFreeHintsCallback *callback);
71
+
72
+#endif
73
+
74
+/*
75
+ * Prompts for input using the given string as the input
76
+ * prompt. Returns when the user has tapped ENTER or (on an empty
77
+ * line) EOF (Ctrl-D on Unix, Ctrl-Z on Windows). Returns either
78
+ * a copy of the entered string (for ENTER) or NULL (on EOF). The
79
+ * caller owns the returned string and must eventually free() it.
80
+ */
5981
char *linenoise(const char *prompt);
60
-void linenoiseFree(void *ptr);
61
-int linenoiseHistoryAdd(const char *line);
62
-int linenoiseHistorySetMaxLen(int len);
63
-int linenoiseHistorySave(const char *filename);
64
-int linenoiseHistoryLoad(const char *filename);
82
+
83
+/**
84
+ * Like linenoise() but starts with an initial buffer.
85
+ */
86
+char *linenoiseWithInitial(const char *prompt, const char *initial);
87
+
88
+/**
89
+ * Clear the screen.
90
+ */
6591
void linenoiseClearScreen(void);
66
-void linenoiseSetMultiLine(int ml);
67
-void linenoisePrintKeyCodes(void);
68
-void linenoiseMaskModeEnable(void);
69
-void linenoiseMaskModeDisable(void);
92
+
93
+/*
94
+ * Adds a copy of the given line of the command history.
95
+ */
96
+int linenoiseHistoryAdd(const char *line);
97
+
98
+/*
99
+ * Sets the maximum length of the command history, in lines.
100
+ * If the history is currently longer, it will be trimmed,
101
+ * retaining only the most recent entries. If len is 0 or less
102
+ * then this function does nothing.
103
+ */
104
+int linenoiseHistorySetMaxLen(int len);
105
+
106
+/*
107
+ * Returns the current maximum length of the history, in lines.
108
+ */
109
+int linenoiseHistoryGetMaxLen(void);
110
+
111
+/*
112
+ * Saves the current contents of the history to the given file.
113
+ * Returns 0 on success.
114
+ */
115
+int linenoiseHistorySave(const char *filename);
116
+
117
+/*
118
+ * Replaces the current history with the contents
119
+ * of the given file. Returns 0 on success.
120
+ */
121
+int linenoiseHistoryLoad(const char *filename);
122
+
123
+/*
124
+ * Frees all history entries, clearing the history.
125
+ */
126
+void linenoiseHistoryFree(void);
127
+
128
+/*
129
+ * Returns a pointer to the list of history entries, writing its
130
+ * length to *len if len is not NULL. The memory is owned by linenoise
131
+ * and must not be freed.
132
+ */
133
+char **linenoiseHistory(int *len);
134
+
135
+/*
136
+ * Returns the number of display columns in the current terminal.
137
+ */
138
+int linenoiseColumns(void);
139
+
140
+/**
141
+ * Enable or disable multiline mode (disabled by default)
142
+ */
143
+void linenoiseSetMultiLine(int enableml);
70144
71145
#ifdef __cplusplus
72146
}
73147
#endif
74148
75149
#endif /* __LINENOISE_H */
76150
--- extsrc/linenoise.h
+++ extsrc/linenoise.h
@@ -1,16 +1,14 @@
1 /* linenoise.h -- VERSION 1.0
2 *
3 * Guerrilla line editing library against the idea that a line editing lib
4 * needs to be 20,000 lines of C code.
5 *
6 * See linenoise.c for more information.
7 *
8 * ------------------------------------------------------------------------
9 *
10 * Copyright (c) 2010-2014, Salvatore Sanfilippo <antirez at gmail dot com>
11 * Copyright (c) 2010-2013, Pieter Noordhuis <pcnoordhuis at gmail dot com>
12 *
13 * All rights reserved.
14 *
15 * Redistribution and use in source and binary forms, with or without
16 * modification, are permitted provided that the following conditions are
@@ -41,35 +39,111 @@
41
42 #ifdef __cplusplus
43 extern "C" {
44 #endif
45
 
46 typedef struct linenoiseCompletions {
47 size_t len;
48 char **cvec;
49 } linenoiseCompletions;
50
51 typedef void(linenoiseCompletionCallback)(const char *, linenoiseCompletions *);
52 typedef char*(linenoiseHintsCallback)(const char *, int *color, int *bold);
53 typedef void(linenoiseFreeHintsCallback)(void *);
54 void linenoiseSetCompletionCallback(linenoiseCompletionCallback *);
55 void linenoiseSetHintsCallback(linenoiseHintsCallback *);
56 void linenoiseSetFreeHintsCallback(linenoiseFreeHintsCallback *);
57 void linenoiseAddCompletion(linenoiseCompletions *, const char *);
58
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
59 char *linenoise(const char *prompt);
60 void linenoiseFree(void *ptr);
61 int linenoiseHistoryAdd(const char *line);
62 int linenoiseHistorySetMaxLen(int len);
63 int linenoiseHistorySave(const char *filename);
64 int linenoiseHistoryLoad(const char *filename);
 
 
 
 
65 void linenoiseClearScreen(void);
66 void linenoiseSetMultiLine(int ml);
67 void linenoisePrintKeyCodes(void);
68 void linenoiseMaskModeEnable(void);
69 void linenoiseMaskModeDisable(void);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
70
71 #ifdef __cplusplus
72 }
73 #endif
74
75 #endif /* __LINENOISE_H */
76
--- extsrc/linenoise.h
+++ extsrc/linenoise.h
@@ -1,16 +1,14 @@
1 /* linenoise.h -- guerrilla line editing library against the idea that a
2 * line editing lib needs to be 20,000 lines of C code.
 
 
3 *
4 * See linenoise.c for more information.
5 *
6 * ------------------------------------------------------------------------
7 *
8 * Copyright (c) 2010, Salvatore Sanfilippo <antirez at gmail dot com>
9 * Copyright (c) 2010, Pieter Noordhuis <pcnoordhuis at gmail dot com>
10 *
11 * All rights reserved.
12 *
13 * Redistribution and use in source and binary forms, with or without
14 * modification, are permitted provided that the following conditions are
@@ -41,35 +39,111 @@
39
40 #ifdef __cplusplus
41 extern "C" {
42 #endif
43
44 #ifndef NO_COMPLETION
45 typedef struct linenoiseCompletions {
46 size_t len;
47 char **cvec;
48 } linenoiseCompletions;
49
50 /*
51 * The callback type for tab completion handlers.
52 */
53 typedef void(linenoiseCompletionCallback)(const char *prefix, linenoiseCompletions *comp, void *userdata);
54
55 /*
56 * Sets the current tab completion handler and returns the previous one, or NULL
57 * if no prior one has been set.
58 */
59 linenoiseCompletionCallback * linenoiseSetCompletionCallback(linenoiseCompletionCallback *comp, void *userdata);
60
61 /*
62 * Adds a copy of the given string to the given completion list. The copy is owned
63 * by the linenoiseCompletions object.
64 */
65 void linenoiseAddCompletion(linenoiseCompletions *comp, const char *str);
66
67 typedef char*(linenoiseHintsCallback)(const char *, int *color, int *bold, void *userdata);
68 typedef void(linenoiseFreeHintsCallback)(void *hint, void *userdata);
69 void linenoiseSetHintsCallback(linenoiseHintsCallback *callback, void *userdata);
70 void linenoiseSetFreeHintsCallback(linenoiseFreeHintsCallback *callback);
71
72 #endif
73
74 /*
75 * Prompts for input using the given string as the input
76 * prompt. Returns when the user has tapped ENTER or (on an empty
77 * line) EOF (Ctrl-D on Unix, Ctrl-Z on Windows). Returns either
78 * a copy of the entered string (for ENTER) or NULL (on EOF). The
79 * caller owns the returned string and must eventually free() it.
80 */
81 char *linenoise(const char *prompt);
82
83 /**
84 * Like linenoise() but starts with an initial buffer.
85 */
86 char *linenoiseWithInitial(const char *prompt, const char *initial);
87
88 /**
89 * Clear the screen.
90 */
91 void linenoiseClearScreen(void);
92
93 /*
94 * Adds a copy of the given line of the command history.
95 */
96 int linenoiseHistoryAdd(const char *line);
97
98 /*
99 * Sets the maximum length of the command history, in lines.
100 * If the history is currently longer, it will be trimmed,
101 * retaining only the most recent entries. If len is 0 or less
102 * then this function does nothing.
103 */
104 int linenoiseHistorySetMaxLen(int len);
105
106 /*
107 * Returns the current maximum length of the history, in lines.
108 */
109 int linenoiseHistoryGetMaxLen(void);
110
111 /*
112 * Saves the current contents of the history to the given file.
113 * Returns 0 on success.
114 */
115 int linenoiseHistorySave(const char *filename);
116
117 /*
118 * Replaces the current history with the contents
119 * of the given file. Returns 0 on success.
120 */
121 int linenoiseHistoryLoad(const char *filename);
122
123 /*
124 * Frees all history entries, clearing the history.
125 */
126 void linenoiseHistoryFree(void);
127
128 /*
129 * Returns a pointer to the list of history entries, writing its
130 * length to *len if len is not NULL. The memory is owned by linenoise
131 * and must not be freed.
132 */
133 char **linenoiseHistory(int *len);
134
135 /*
136 * Returns the number of display columns in the current terminal.
137 */
138 int linenoiseColumns(void);
139
140 /**
141 * Enable or disable multiline mode (disabled by default)
142 */
143 void linenoiseSetMultiLine(int enableml);
144
145 #ifdef __cplusplus
146 }
147 #endif
148
149 #endif /* __LINENOISE_H */
150
+116 -8
--- extsrc/shell.c
+++ extsrc/shell.c
@@ -14068,11 +14068,10 @@
1406814068
}
1406914069
1407014070
#endif /* ifndef SQLITE_OMIT_VIRTUALTABLE */
1407114071
1407214072
/************************* End ../ext/expert/sqlite3expert.c ********************/
14073
-
1407414073
/************************* Begin ../ext/intck/sqlite3intck.h ******************/
1407514074
/*
1407614075
** 2024-02-08
1407714076
**
1407814077
** The author disclaims copyright to this source code. In place of
@@ -15186,10 +15185,110 @@
1518615185
}
1518715186
return p->zTestSql;
1518815187
}
1518915188
1519015189
/************************* End ../ext/intck/sqlite3intck.c ********************/
15190
+/************************* Begin ../ext/misc/stmtrand.c ******************/
15191
+/*
15192
+** 2024-05-24
15193
+**
15194
+** The author disclaims copyright to this source code. In place of
15195
+** a legal notice, here is a blessing:
15196
+**
15197
+** May you do good and not evil.
15198
+** May you find forgiveness for yourself and forgive others.
15199
+** May you share freely, never taking more than you give.
15200
+**
15201
+******************************************************************************
15202
+**
15203
+** An SQL function that return pseudo-random non-negative integers.
15204
+**
15205
+** SELECT stmtrand(123);
15206
+**
15207
+** A special feature of this function is that the same sequence of random
15208
+** integers is returned for each invocation of the statement. This makes
15209
+** the results repeatable, and hence useful for testing. The argument is
15210
+** an integer which is the seed for the random number sequence. The seed
15211
+** is used by the first invocation of this function only and is ignored
15212
+** for all subsequent calls within the same statement.
15213
+**
15214
+** Resetting a statement (sqlite3_reset()) also resets the random number
15215
+** sequence.
15216
+*/
15217
+/* #include "sqlite3ext.h" */
15218
+SQLITE_EXTENSION_INIT1
15219
+#include <assert.h>
15220
+#include <string.h>
15221
+
15222
+/* State of the pseudo-random number generator */
15223
+typedef struct Stmtrand {
15224
+ unsigned int x, y;
15225
+} Stmtrand;
15226
+
15227
+/* auxdata key */
15228
+#define STMTRAND_KEY (-4418371)
15229
+
15230
+/*
15231
+** Function: stmtrand(SEED)
15232
+**
15233
+** Return a pseudo-random number.
15234
+*/
15235
+static void stmtrandFunc(
15236
+ sqlite3_context *context,
15237
+ int argc,
15238
+ sqlite3_value **argv
15239
+){
15240
+ Stmtrand *p;
15241
+
15242
+ p = (Stmtrand*)sqlite3_get_auxdata(context, STMTRAND_KEY);
15243
+ if( p==0 ){
15244
+ unsigned int seed;
15245
+ p = sqlite3_malloc( sizeof(*p) );
15246
+ if( p==0 ){
15247
+ sqlite3_result_error_nomem(context);
15248
+ return;
15249
+ }
15250
+ if( argc>=1 ){
15251
+ seed = (unsigned int)sqlite3_value_int(argv[0]);
15252
+ }else{
15253
+ seed = 0;
15254
+ }
15255
+ p->x = seed | 1;
15256
+ p->y = seed;
15257
+ sqlite3_set_auxdata(context, STMTRAND_KEY, p, sqlite3_free);
15258
+ p = (Stmtrand*)sqlite3_get_auxdata(context, STMTRAND_KEY);
15259
+ if( p==0 ){
15260
+ sqlite3_result_error_nomem(context);
15261
+ return;
15262
+ }
15263
+ }
15264
+ p->x = (p->x>>1) ^ ((1+~(p->x&1)) & 0xd0000001);
15265
+ p->y = p->y*1103515245 + 12345;
15266
+ sqlite3_result_int(context, (int)((p->x ^ p->y)&0x7fffffff));
15267
+}
15268
+
15269
+#ifdef _WIN32
15270
+
15271
+#endif
15272
+int sqlite3_stmtrand_init(
15273
+ sqlite3 *db,
15274
+ char **pzErrMsg,
15275
+ const sqlite3_api_routines *pApi
15276
+){
15277
+ int rc = SQLITE_OK;
15278
+ SQLITE_EXTENSION_INIT2(pApi);
15279
+ (void)pzErrMsg; /* Unused parameter */
15280
+ rc = sqlite3_create_function(db, "stmtrand", 1, SQLITE_UTF8, 0,
15281
+ stmtrandFunc, 0, 0);
15282
+ if( rc==SQLITE_OK ){
15283
+ rc = sqlite3_create_function(db, "stmtrand", 0, SQLITE_UTF8, 0,
15284
+ stmtrandFunc, 0, 0);
15285
+ }
15286
+ return rc;
15287
+}
15288
+
15289
+/************************* End ../ext/misc/stmtrand.c ********************/
1519115290
1519215291
#if !defined(SQLITE_OMIT_VIRTUALTABLE) && defined(SQLITE_ENABLE_DBPAGE_VTAB)
1519315292
#define SQLITE_SHELL_HAVE_RECOVER 1
1519415293
#else
1519515294
#define SQLITE_SHELL_HAVE_RECOVER 0
@@ -23470,10 +23569,11 @@
2347023569
#ifndef SQLITE_OMIT_LOAD_EXTENSION
2347123570
sqlite3_enable_load_extension(p->db, 1);
2347223571
#endif
2347323572
sqlite3_shathree_init(p->db, 0, 0);
2347423573
sqlite3_uint_init(p->db, 0, 0);
23574
+ sqlite3_stmtrand_init(p->db, 0, 0);
2347523575
sqlite3_decimal_init(p->db, 0, 0);
2347623576
sqlite3_base64_init(p->db, 0, 0);
2347723577
sqlite3_base85_init(p->db, 0, 0);
2347823578
sqlite3_regexp_init(p->db, 0, 0);
2347923579
sqlite3_ieee_init(p->db, 0, 0);
@@ -23623,19 +23723,22 @@
2362323723
return rl_completion_matches(zText, readline_completion_generator);
2362423724
}
2362523725
2362623726
#elif HAVE_LINENOISE
2362723727
/*
23628
-** Linenoise completion callback
23728
+** Linenoise completion callback. Note that the 3rd argument is from
23729
+** the "msteveb" version of linenoise, not the "antirez" version.
2362923730
*/
23630
-static void linenoise_completion(const char *zLine, linenoiseCompletions *lc){
23731
+static void linenoise_completion(const char *zLine, linenoiseCompletions *lc,
23732
+ void *pUserData){
2363123733
i64 nLine = strlen(zLine);
2363223734
i64 i, iStart;
2363323735
sqlite3_stmt *pStmt = 0;
2363423736
char *zSql;
2363523737
char zBuf[1000];
2363623738
23739
+ UNUSED_PARAMETER(pUserData);
2363723740
if( nLine>(i64)sizeof(zBuf)-30 ) return;
2363823741
if( zLine[0]=='.' || zLine[0]=='#') return;
2363923742
for(i=nLine-1; i>=0 && (isalnum(zLine[i]) || zLine[i]=='_'); i--){}
2364023743
if( i==nLine-1 ) return;
2364123744
iStart = i+1;
@@ -27083,11 +27186,10 @@
2708327186
zTable, zSchema);
2708427187
if( zSql==0 ){
2708527188
import_cleanup(&sCtx);
2708627189
shell_out_of_memory();
2708727190
}
27088
- nByte = strlen(zSql);
2708927191
rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0);
2709027192
sqlite3_free(zSql);
2709127193
zSql = 0;
2709227194
if( rc ){
2709327195
if (pStmt) sqlite3_finalize(pStmt);
@@ -27102,28 +27204,34 @@
2710227204
nCol = 0;
2710327205
}
2710427206
sqlite3_finalize(pStmt);
2710527207
pStmt = 0;
2710627208
if( nCol==0 ) return 0; /* no columns, no error */
27107
- zSql = sqlite3_malloc64( nByte*2 + 20 + nCol*2 );
27209
+
27210
+ nByte = 64 /* space for "INSERT INTO", "VALUES(", ")\0" */
27211
+ + (zSchema ? strlen(zSchema)*2 + 2: 0) /* Quoted schema name */
27212
+ + strlen(zTable)*2 + 2 /* Quoted table name */
27213
+ + nCol*2; /* Space for ",?" for each column */
27214
+ zSql = sqlite3_malloc64( nByte );
2710827215
if( zSql==0 ){
2710927216
import_cleanup(&sCtx);
2711027217
shell_out_of_memory();
2711127218
}
2711227219
if( zSchema ){
27113
- sqlite3_snprintf(nByte+20, zSql, "INSERT INTO \"%w\".\"%w\" VALUES(?",
27220
+ sqlite3_snprintf(nByte, zSql, "INSERT INTO \"%w\".\"%w\" VALUES(?",
2711427221
zSchema, zTable);
2711527222
}else{
27116
- sqlite3_snprintf(nByte+20, zSql, "INSERT INTO \"%w\" VALUES(?", zTable);
27223
+ sqlite3_snprintf(nByte, zSql, "INSERT INTO \"%w\" VALUES(?", zTable);
2711727224
}
2711827225
j = strlen30(zSql);
2711927226
for(i=1; i<nCol; i++){
2712027227
zSql[j++] = ',';
2712127228
zSql[j++] = '?';
2712227229
}
2712327230
zSql[j++] = ')';
2712427231
zSql[j] = 0;
27232
+ assert( j<nByte );
2712527233
if( eVerbose>=2 ){
2712627234
oputf("Insert using: %s\n", zSql);
2712727235
}
2712827236
rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0);
2712927237
sqlite3_free(zSql);
@@ -30899,11 +31007,11 @@
3089931007
}
3090031008
if( zHistory ){ shell_read_history(zHistory); }
3090131009
#if HAVE_READLINE || HAVE_EDITLINE
3090231010
rl_attempted_completion_function = readline_completion;
3090331011
#elif HAVE_LINENOISE
30904
- linenoiseSetCompletionCallback(linenoise_completion);
31012
+ linenoiseSetCompletionCallback(linenoise_completion, NULL);
3090531013
#endif
3090631014
data.in = 0;
3090731015
rc = process_input(&data);
3090831016
if( zHistory ){
3090931017
shell_stifle_history(2000);
3091031018
--- extsrc/shell.c
+++ extsrc/shell.c
@@ -14068,11 +14068,10 @@
14068 }
14069
14070 #endif /* ifndef SQLITE_OMIT_VIRTUALTABLE */
14071
14072 /************************* End ../ext/expert/sqlite3expert.c ********************/
14073
14074 /************************* Begin ../ext/intck/sqlite3intck.h ******************/
14075 /*
14076 ** 2024-02-08
14077 **
14078 ** The author disclaims copyright to this source code. In place of
@@ -15186,10 +15185,110 @@
15186 }
15187 return p->zTestSql;
15188 }
15189
15190 /************************* End ../ext/intck/sqlite3intck.c ********************/
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
15191
15192 #if !defined(SQLITE_OMIT_VIRTUALTABLE) && defined(SQLITE_ENABLE_DBPAGE_VTAB)
15193 #define SQLITE_SHELL_HAVE_RECOVER 1
15194 #else
15195 #define SQLITE_SHELL_HAVE_RECOVER 0
@@ -23470,10 +23569,11 @@
23470 #ifndef SQLITE_OMIT_LOAD_EXTENSION
23471 sqlite3_enable_load_extension(p->db, 1);
23472 #endif
23473 sqlite3_shathree_init(p->db, 0, 0);
23474 sqlite3_uint_init(p->db, 0, 0);
 
23475 sqlite3_decimal_init(p->db, 0, 0);
23476 sqlite3_base64_init(p->db, 0, 0);
23477 sqlite3_base85_init(p->db, 0, 0);
23478 sqlite3_regexp_init(p->db, 0, 0);
23479 sqlite3_ieee_init(p->db, 0, 0);
@@ -23623,19 +23723,22 @@
23623 return rl_completion_matches(zText, readline_completion_generator);
23624 }
23625
23626 #elif HAVE_LINENOISE
23627 /*
23628 ** Linenoise completion callback
 
23629 */
23630 static void linenoise_completion(const char *zLine, linenoiseCompletions *lc){
 
23631 i64 nLine = strlen(zLine);
23632 i64 i, iStart;
23633 sqlite3_stmt *pStmt = 0;
23634 char *zSql;
23635 char zBuf[1000];
23636
 
23637 if( nLine>(i64)sizeof(zBuf)-30 ) return;
23638 if( zLine[0]=='.' || zLine[0]=='#') return;
23639 for(i=nLine-1; i>=0 && (isalnum(zLine[i]) || zLine[i]=='_'); i--){}
23640 if( i==nLine-1 ) return;
23641 iStart = i+1;
@@ -27083,11 +27186,10 @@
27083 zTable, zSchema);
27084 if( zSql==0 ){
27085 import_cleanup(&sCtx);
27086 shell_out_of_memory();
27087 }
27088 nByte = strlen(zSql);
27089 rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0);
27090 sqlite3_free(zSql);
27091 zSql = 0;
27092 if( rc ){
27093 if (pStmt) sqlite3_finalize(pStmt);
@@ -27102,28 +27204,34 @@
27102 nCol = 0;
27103 }
27104 sqlite3_finalize(pStmt);
27105 pStmt = 0;
27106 if( nCol==0 ) return 0; /* no columns, no error */
27107 zSql = sqlite3_malloc64( nByte*2 + 20 + nCol*2 );
 
 
 
 
 
27108 if( zSql==0 ){
27109 import_cleanup(&sCtx);
27110 shell_out_of_memory();
27111 }
27112 if( zSchema ){
27113 sqlite3_snprintf(nByte+20, zSql, "INSERT INTO \"%w\".\"%w\" VALUES(?",
27114 zSchema, zTable);
27115 }else{
27116 sqlite3_snprintf(nByte+20, zSql, "INSERT INTO \"%w\" VALUES(?", zTable);
27117 }
27118 j = strlen30(zSql);
27119 for(i=1; i<nCol; i++){
27120 zSql[j++] = ',';
27121 zSql[j++] = '?';
27122 }
27123 zSql[j++] = ')';
27124 zSql[j] = 0;
 
27125 if( eVerbose>=2 ){
27126 oputf("Insert using: %s\n", zSql);
27127 }
27128 rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0);
27129 sqlite3_free(zSql);
@@ -30899,11 +31007,11 @@
30899 }
30900 if( zHistory ){ shell_read_history(zHistory); }
30901 #if HAVE_READLINE || HAVE_EDITLINE
30902 rl_attempted_completion_function = readline_completion;
30903 #elif HAVE_LINENOISE
30904 linenoiseSetCompletionCallback(linenoise_completion);
30905 #endif
30906 data.in = 0;
30907 rc = process_input(&data);
30908 if( zHistory ){
30909 shell_stifle_history(2000);
30910
--- extsrc/shell.c
+++ extsrc/shell.c
@@ -14068,11 +14068,10 @@
14068 }
14069
14070 #endif /* ifndef SQLITE_OMIT_VIRTUALTABLE */
14071
14072 /************************* End ../ext/expert/sqlite3expert.c ********************/
 
14073 /************************* Begin ../ext/intck/sqlite3intck.h ******************/
14074 /*
14075 ** 2024-02-08
14076 **
14077 ** The author disclaims copyright to this source code. In place of
@@ -15186,10 +15185,110 @@
15185 }
15186 return p->zTestSql;
15187 }
15188
15189 /************************* End ../ext/intck/sqlite3intck.c ********************/
15190 /************************* Begin ../ext/misc/stmtrand.c ******************/
15191 /*
15192 ** 2024-05-24
15193 **
15194 ** The author disclaims copyright to this source code. In place of
15195 ** a legal notice, here is a blessing:
15196 **
15197 ** May you do good and not evil.
15198 ** May you find forgiveness for yourself and forgive others.
15199 ** May you share freely, never taking more than you give.
15200 **
15201 ******************************************************************************
15202 **
15203 ** An SQL function that return pseudo-random non-negative integers.
15204 **
15205 ** SELECT stmtrand(123);
15206 **
15207 ** A special feature of this function is that the same sequence of random
15208 ** integers is returned for each invocation of the statement. This makes
15209 ** the results repeatable, and hence useful for testing. The argument is
15210 ** an integer which is the seed for the random number sequence. The seed
15211 ** is used by the first invocation of this function only and is ignored
15212 ** for all subsequent calls within the same statement.
15213 **
15214 ** Resetting a statement (sqlite3_reset()) also resets the random number
15215 ** sequence.
15216 */
15217 /* #include "sqlite3ext.h" */
15218 SQLITE_EXTENSION_INIT1
15219 #include <assert.h>
15220 #include <string.h>
15221
15222 /* State of the pseudo-random number generator */
15223 typedef struct Stmtrand {
15224 unsigned int x, y;
15225 } Stmtrand;
15226
15227 /* auxdata key */
15228 #define STMTRAND_KEY (-4418371)
15229
15230 /*
15231 ** Function: stmtrand(SEED)
15232 **
15233 ** Return a pseudo-random number.
15234 */
15235 static void stmtrandFunc(
15236 sqlite3_context *context,
15237 int argc,
15238 sqlite3_value **argv
15239 ){
15240 Stmtrand *p;
15241
15242 p = (Stmtrand*)sqlite3_get_auxdata(context, STMTRAND_KEY);
15243 if( p==0 ){
15244 unsigned int seed;
15245 p = sqlite3_malloc( sizeof(*p) );
15246 if( p==0 ){
15247 sqlite3_result_error_nomem(context);
15248 return;
15249 }
15250 if( argc>=1 ){
15251 seed = (unsigned int)sqlite3_value_int(argv[0]);
15252 }else{
15253 seed = 0;
15254 }
15255 p->x = seed | 1;
15256 p->y = seed;
15257 sqlite3_set_auxdata(context, STMTRAND_KEY, p, sqlite3_free);
15258 p = (Stmtrand*)sqlite3_get_auxdata(context, STMTRAND_KEY);
15259 if( p==0 ){
15260 sqlite3_result_error_nomem(context);
15261 return;
15262 }
15263 }
15264 p->x = (p->x>>1) ^ ((1+~(p->x&1)) & 0xd0000001);
15265 p->y = p->y*1103515245 + 12345;
15266 sqlite3_result_int(context, (int)((p->x ^ p->y)&0x7fffffff));
15267 }
15268
15269 #ifdef _WIN32
15270
15271 #endif
15272 int sqlite3_stmtrand_init(
15273 sqlite3 *db,
15274 char **pzErrMsg,
15275 const sqlite3_api_routines *pApi
15276 ){
15277 int rc = SQLITE_OK;
15278 SQLITE_EXTENSION_INIT2(pApi);
15279 (void)pzErrMsg; /* Unused parameter */
15280 rc = sqlite3_create_function(db, "stmtrand", 1, SQLITE_UTF8, 0,
15281 stmtrandFunc, 0, 0);
15282 if( rc==SQLITE_OK ){
15283 rc = sqlite3_create_function(db, "stmtrand", 0, SQLITE_UTF8, 0,
15284 stmtrandFunc, 0, 0);
15285 }
15286 return rc;
15287 }
15288
15289 /************************* End ../ext/misc/stmtrand.c ********************/
15290
15291 #if !defined(SQLITE_OMIT_VIRTUALTABLE) && defined(SQLITE_ENABLE_DBPAGE_VTAB)
15292 #define SQLITE_SHELL_HAVE_RECOVER 1
15293 #else
15294 #define SQLITE_SHELL_HAVE_RECOVER 0
@@ -23470,10 +23569,11 @@
23569 #ifndef SQLITE_OMIT_LOAD_EXTENSION
23570 sqlite3_enable_load_extension(p->db, 1);
23571 #endif
23572 sqlite3_shathree_init(p->db, 0, 0);
23573 sqlite3_uint_init(p->db, 0, 0);
23574 sqlite3_stmtrand_init(p->db, 0, 0);
23575 sqlite3_decimal_init(p->db, 0, 0);
23576 sqlite3_base64_init(p->db, 0, 0);
23577 sqlite3_base85_init(p->db, 0, 0);
23578 sqlite3_regexp_init(p->db, 0, 0);
23579 sqlite3_ieee_init(p->db, 0, 0);
@@ -23623,19 +23723,22 @@
23723 return rl_completion_matches(zText, readline_completion_generator);
23724 }
23725
23726 #elif HAVE_LINENOISE
23727 /*
23728 ** Linenoise completion callback. Note that the 3rd argument is from
23729 ** the "msteveb" version of linenoise, not the "antirez" version.
23730 */
23731 static void linenoise_completion(const char *zLine, linenoiseCompletions *lc,
23732 void *pUserData){
23733 i64 nLine = strlen(zLine);
23734 i64 i, iStart;
23735 sqlite3_stmt *pStmt = 0;
23736 char *zSql;
23737 char zBuf[1000];
23738
23739 UNUSED_PARAMETER(pUserData);
23740 if( nLine>(i64)sizeof(zBuf)-30 ) return;
23741 if( zLine[0]=='.' || zLine[0]=='#') return;
23742 for(i=nLine-1; i>=0 && (isalnum(zLine[i]) || zLine[i]=='_'); i--){}
23743 if( i==nLine-1 ) return;
23744 iStart = i+1;
@@ -27083,11 +27186,10 @@
27186 zTable, zSchema);
27187 if( zSql==0 ){
27188 import_cleanup(&sCtx);
27189 shell_out_of_memory();
27190 }
 
27191 rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0);
27192 sqlite3_free(zSql);
27193 zSql = 0;
27194 if( rc ){
27195 if (pStmt) sqlite3_finalize(pStmt);
@@ -27102,28 +27204,34 @@
27204 nCol = 0;
27205 }
27206 sqlite3_finalize(pStmt);
27207 pStmt = 0;
27208 if( nCol==0 ) return 0; /* no columns, no error */
27209
27210 nByte = 64 /* space for "INSERT INTO", "VALUES(", ")\0" */
27211 + (zSchema ? strlen(zSchema)*2 + 2: 0) /* Quoted schema name */
27212 + strlen(zTable)*2 + 2 /* Quoted table name */
27213 + nCol*2; /* Space for ",?" for each column */
27214 zSql = sqlite3_malloc64( nByte );
27215 if( zSql==0 ){
27216 import_cleanup(&sCtx);
27217 shell_out_of_memory();
27218 }
27219 if( zSchema ){
27220 sqlite3_snprintf(nByte, zSql, "INSERT INTO \"%w\".\"%w\" VALUES(?",
27221 zSchema, zTable);
27222 }else{
27223 sqlite3_snprintf(nByte, zSql, "INSERT INTO \"%w\" VALUES(?", zTable);
27224 }
27225 j = strlen30(zSql);
27226 for(i=1; i<nCol; i++){
27227 zSql[j++] = ',';
27228 zSql[j++] = '?';
27229 }
27230 zSql[j++] = ')';
27231 zSql[j] = 0;
27232 assert( j<nByte );
27233 if( eVerbose>=2 ){
27234 oputf("Insert using: %s\n", zSql);
27235 }
27236 rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0);
27237 sqlite3_free(zSql);
@@ -30899,11 +31007,11 @@
31007 }
31008 if( zHistory ){ shell_read_history(zHistory); }
31009 #if HAVE_READLINE || HAVE_EDITLINE
31010 rl_attempted_completion_function = readline_completion;
31011 #elif HAVE_LINENOISE
31012 linenoiseSetCompletionCallback(linenoise_completion, NULL);
31013 #endif
31014 data.in = 0;
31015 rc = process_input(&data);
31016 if( zHistory ){
31017 shell_stifle_history(2000);
31018

Keyboard Shortcuts

Open search /
Next entry (timeline) j
Previous entry (timeline) k
Open focused entry Enter
Show this help ?
Toggle theme Top nav button