Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/bc/include/history.h
39507 views
1
/*
2
* *****************************************************************************
3
*
4
* SPDX-License-Identifier: BSD-2-Clause
5
*
6
* Copyright (c) 2018-2025 Gavin D. Howard and contributors.
7
*
8
* Redistribution and use in source and binary forms, with or without
9
* modification, are permitted provided that the following conditions are met:
10
*
11
* * Redistributions of source code must retain the above copyright notice, this
12
* list of conditions and the following disclaimer.
13
*
14
* * Redistributions in binary form must reproduce the above copyright notice,
15
* this list of conditions and the following disclaimer in the documentation
16
* and/or other materials provided with the distribution.
17
*
18
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
22
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28
* POSSIBILITY OF SUCH DAMAGE.
29
*
30
* *****************************************************************************
31
*
32
* Adapted from the following:
33
*
34
* linenoise.c -- guerrilla line editing library against the idea that a
35
* line editing lib needs to be 20,000 lines of C code.
36
*
37
* You can find the original source code at:
38
* http://github.com/antirez/linenoise
39
*
40
* You can find the fork that this code is based on at:
41
* https://github.com/rain-1/linenoise-mob
42
*
43
* ------------------------------------------------------------------------
44
*
45
* This code is also under the following license:
46
*
47
* Copyright (c) 2010-2016, Salvatore Sanfilippo <antirez at gmail dot com>
48
* Copyright (c) 2010-2013, Pieter Noordhuis <pcnoordhuis at gmail dot com>
49
*
50
* Redistribution and use in source and binary forms, with or without
51
* modification, are permitted provided that the following conditions are
52
* met:
53
*
54
* * Redistributions of source code must retain the above copyright
55
* notice, this list of conditions and the following disclaimer.
56
*
57
* * Redistributions in binary form must reproduce the above copyright
58
* notice, this list of conditions and the following disclaimer in the
59
* documentation and/or other materials provided with the distribution.
60
*
61
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
62
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
63
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
64
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
65
* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
66
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
67
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
68
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
69
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
70
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
71
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
72
*
73
* *****************************************************************************
74
*
75
* Definitions for line history.
76
*
77
*/
78
79
#ifndef BC_HISTORY_H
80
#define BC_HISTORY_H
81
82
// These must come before the #if BC_ENABLE_LINE_LIB below because status.h
83
// defines it.
84
#include <status.h>
85
#include <vector.h>
86
87
#if BC_ENABLE_LINE_LIB
88
89
#include <stdbool.h>
90
#include <setjmp.h>
91
#include <signal.h>
92
93
extern sigjmp_buf bc_history_jmpbuf;
94
extern volatile sig_atomic_t bc_history_inlinelib;
95
96
#endif // BC_ENABLE_LINE_LIB
97
98
#if BC_ENABLE_EDITLINE
99
100
#include <stdio.h>
101
#include <histedit.h>
102
103
/**
104
* The history struct for editline.
105
*/
106
typedef struct BcHistory
107
{
108
/// A place to store the current line.
109
EditLine* el;
110
111
/// The history.
112
History* hist;
113
114
/// Whether the terminal is bad. This is more or less not used.
115
bool badTerm;
116
117
} BcHistory;
118
119
// The path to the editrc and its length.
120
extern const char bc_history_editrc[];
121
extern const size_t bc_history_editrc_len;
122
123
#else // BC_ENABLE_EDITLINE
124
125
#if BC_ENABLE_READLINE
126
127
#include <stdio.h>
128
#include <readline/readline.h>
129
#include <readline/history.h>
130
131
/**
132
* The history struct for readline.
133
*/
134
typedef struct BcHistory
135
{
136
/// A place to store the current line.
137
char* line;
138
139
/// Whether the terminal is bad. This is more or less not used.
140
bool badTerm;
141
142
} BcHistory;
143
144
#else // BC_ENABLE_READLINE
145
146
#if BC_ENABLE_HISTORY
147
148
#include <stddef.h>
149
150
#include <signal.h>
151
152
#ifndef _WIN32
153
#include <termios.h>
154
#include <time.h>
155
#include <unistd.h>
156
#include <sys/select.h>
157
#else // _WIN32
158
159
#ifndef WIN32_LEAN_AND_MEAN
160
#define WIN32_LEAN_AND_MEAN
161
#endif // WIN32_LEAN_AND_MEAN
162
163
#include <Windows.h>
164
#include <io.h>
165
#include <conio.h>
166
167
#define strncasecmp _strnicmp
168
#define strcasecmp _stricmp
169
170
#endif // _WIN32
171
172
#include <status.h>
173
#include <vector.h>
174
#include <read.h>
175
176
/// Default columns.
177
#define BC_HIST_DEF_COLS (80)
178
179
/// Max number of history entries.
180
#define BC_HIST_MAX_LEN (128)
181
182
/// Max length of a line.
183
#define BC_HIST_MAX_LINE (4095)
184
185
/// Max size for cursor position buffer.
186
#define BC_HIST_SEQ_SIZE (64)
187
188
/**
189
* The number of entries in the history.
190
* @param h The history data.
191
*/
192
#define BC_HIST_BUF_LEN(h) ((h)->buf.len - 1)
193
194
/**
195
* Read n characters into s and check the error.
196
* @param s The buffer to read into.
197
* @param n The number of bytes to read.
198
* @return True if there was an error, false otherwise.
199
*/
200
#define BC_HIST_READ(s, n) (bc_history_read((s), (n)) == -1)
201
202
/// Markers for direction when using arrow keys.
203
#define BC_HIST_NEXT (false)
204
#define BC_HIST_PREV (true)
205
206
#if BC_DEBUG_CODE
207
208
// These are just for debugging.
209
210
#define BC_HISTORY_DEBUG_BUF_SIZE (1024)
211
212
// clang-format off
213
#define lndebug(...) \
214
do \
215
{ \
216
if (bc_history_debug_fp.fd == 0) \
217
{ \
218
bc_history_debug_buf = bc_vm_malloc(BC_HISTORY_DEBUG_BUF_SIZE); \
219
bc_file_init(&bc_history_debug_fp, \
220
open("/tmp/lndebug.txt", O_APPEND), \
221
BC_HISTORY_DEBUG_BUF_SIZE); \
222
bc_file_printf(&bc_history_debug_fp, \
223
"[%zu %zu %zu] p: %d, rows: %d, " \
224
"rpos: %d, max: %zu, oldmax: %d\n", \
225
l->len, l->pos, l->oldcolpos, plen, rows, rpos, \
226
l->maxrows, old_rows); \
227
} \
228
bc_file_printf(&bc_history_debug_fp, ", " __VA_ARGS__); \
229
bc_file_flush(&bc_history_debug_fp); \
230
} \
231
while (0)
232
#else // BC_DEBUG_CODE
233
#define lndebug(fmt, ...)
234
#endif // BC_DEBUG_CODE
235
// clang-format on
236
237
/// An enum of useful actions. To understand what these mean, check terminal
238
/// emulators for their shortcuts or the VT100 codes.
239
typedef enum BcHistoryAction
240
{
241
BC_ACTION_NULL = 0,
242
BC_ACTION_CTRL_A = 1,
243
BC_ACTION_CTRL_B = 2,
244
BC_ACTION_CTRL_C = 3,
245
BC_ACTION_CTRL_D = 4,
246
BC_ACTION_CTRL_E = 5,
247
BC_ACTION_CTRL_F = 6,
248
BC_ACTION_CTRL_H = 8,
249
BC_ACTION_TAB = 9,
250
BC_ACTION_LINE_FEED = 10,
251
BC_ACTION_CTRL_K = 11,
252
BC_ACTION_CTRL_L = 12,
253
BC_ACTION_ENTER = 13,
254
BC_ACTION_CTRL_N = 14,
255
BC_ACTION_CTRL_P = 16,
256
BC_ACTION_CTRL_S = 19,
257
BC_ACTION_CTRL_T = 20,
258
BC_ACTION_CTRL_U = 21,
259
BC_ACTION_CTRL_W = 23,
260
BC_ACTION_CTRL_Z = 26,
261
BC_ACTION_ESC = 27,
262
BC_ACTION_CTRL_BSLASH = 28,
263
BC_ACTION_BACKSPACE = 127
264
265
} BcHistoryAction;
266
267
/**
268
* This represents the state during line editing. We pass this state
269
* to functions implementing specific editing functionalities.
270
*/
271
typedef struct BcHistory
272
{
273
/// Edited line buffer.
274
BcVec buf;
275
276
/// The history.
277
BcVec history;
278
279
/// Any material printed without a trailing newline.
280
BcVec extras;
281
282
/// Prompt to display.
283
const char* prompt;
284
285
/// Prompt length.
286
size_t plen;
287
288
/// Prompt column length.
289
size_t pcol;
290
291
/// Current cursor position.
292
size_t pos;
293
294
/// Previous refresh cursor column position.
295
size_t oldcolpos;
296
297
/// Number of columns in terminal.
298
size_t cols;
299
300
/// The history index we are currently editing.
301
size_t idx;
302
303
#ifndef _WIN32
304
/// The original terminal state.
305
struct termios orig_termios;
306
#else // _WIN32
307
/// The original input console mode.
308
DWORD orig_in;
309
310
/// The original output console mode.
311
DWORD orig_out;
312
#endif // _WIN32
313
314
/// These next two are here because pahole found a 4 byte hole here.
315
316
/// Whether we are in rawmode.
317
bool rawMode;
318
319
/// Whether the terminal is bad.
320
bool badTerm;
321
322
#ifndef _WIN32
323
/// This is to check if stdin has more data.
324
fd_set rdset;
325
326
/// This is to check if stdin has more data.
327
struct timespec ts;
328
329
/// This is to check if stdin has more data.
330
sigset_t sigmask;
331
#endif // _WIN32
332
333
} BcHistory;
334
335
/**
336
* Frees strings used by history.
337
* @param str The string to free.
338
*/
339
void
340
bc_history_string_free(void* str);
341
342
// A list of terminals that don't work.
343
extern const char* bc_history_bad_terms[];
344
345
// A tab in history and its length.
346
extern const char bc_history_tab[];
347
extern const size_t bc_history_tab_len;
348
349
// A ctrl+c string.
350
extern const char bc_history_ctrlc[];
351
352
// UTF-8 data arrays.
353
extern const uint32_t bc_history_wchars[][2];
354
extern const size_t bc_history_wchars_len;
355
extern const uint32_t bc_history_combo_chars[];
356
extern const size_t bc_history_combo_chars_len;
357
358
#if BC_DEBUG_CODE
359
360
// Debug data.
361
extern BcFile bc_history_debug_fp;
362
extern char* bc_history_debug_buf;
363
364
/**
365
* A function to print keycodes for debugging.
366
* @param h The history data.
367
*/
368
void
369
bc_history_printKeyCodes(BcHistory* h);
370
371
#endif // BC_DEBUG_CODE
372
373
#endif // BC_ENABLE_HISTORY
374
375
#endif // BC_ENABLE_READLINE
376
377
#endif // BC_ENABLE_EDITLINE
378
379
#if BC_ENABLE_HISTORY
380
381
/**
382
* Get a line from stdin using history. This returns a status because I don't
383
* want to throw errors while the terminal is in raw mode.
384
* @param h The history data.
385
* @param vec A vector to put the line into.
386
* @param prompt The prompt to display, if desired.
387
* @return A status indicating an error, if any. Returning a status here
388
* is better because if we throw an error out of history, we
389
* leave the terminal in raw mode or in some other half-baked
390
* state.
391
*/
392
BcStatus
393
bc_history_line(BcHistory* h, BcVec* vec, const char* prompt);
394
395
/**
396
* Initialize history data.
397
* @param h The struct to initialize.
398
*/
399
void
400
bc_history_init(BcHistory* h);
401
402
/**
403
* Free history data (and recook the terminal).
404
* @param h The struct to free.
405
*/
406
void
407
bc_history_free(BcHistory* h);
408
409
#endif // BC_ENABLE_HISTORY
410
411
#endif // BC_HISTORY_H
412
413