history.c (f53b5fe7865f4e4240e40ba0f6345f81d337a823) history.c (d101cdd6edd782f6ec56eef63ed91abd77a8b317)
1/*
2 * *****************************************************************************
3 *
4 * SPDX-License-Identifier: BSD-2-Clause
5 *
1/*
2 * *****************************************************************************
3 *
4 * SPDX-License-Identifier: BSD-2-Clause
5 *
6 * Copyright (c) 2018-2021 Gavin D. Howard and contributors.
6 * Copyright (c) 2018-2023 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,

--- 139 unchanged lines hidden (view full) ---

154#include <vm.h>
155
156sigjmp_buf bc_history_jmpbuf;
157volatile sig_atomic_t bc_history_inlinelib;
158
159static char* bc_history_prompt;
160static char bc_history_no_prompt[] = "";
161static HistEvent bc_history_event;
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,

--- 139 unchanged lines hidden (view full) ---

154#include <vm.h>
155
156sigjmp_buf bc_history_jmpbuf;
157volatile sig_atomic_t bc_history_inlinelib;
158
159static char* bc_history_prompt;
160static char bc_history_no_prompt[] = "";
161static HistEvent bc_history_event;
162static bool bc_history_use_prompt;
162
163static char*
164bc_history_promptFunc(EditLine* el)
165{
166 BC_UNUSED(el);
163
164static char*
165bc_history_promptFunc(EditLine* el)
166{
167 BC_UNUSED(el);
167 return BC_PROMPT ? bc_history_prompt : bc_history_no_prompt;
168 return BC_PROMPT && bc_history_use_prompt ? bc_history_prompt :
169 bc_history_no_prompt;
168}
169
170void
171bc_history_init(BcHistory* h)
172{
173 BcVec v;
174 char* home;
175

--- 14 unchanged lines hidden (view full) ---

190 {
191 bc_vec_string(&v, strlen(home), home);
192 bc_vec_concat(&v, bc_history_editrc);
193 }
194
195 h->hist = history_init();
196 if (BC_ERR(h->hist == NULL)) bc_vm_fatalError(BC_ERR_FATAL_ALLOC_ERR);
197
170}
171
172void
173bc_history_init(BcHistory* h)
174{
175 BcVec v;
176 char* home;
177

--- 14 unchanged lines hidden (view full) ---

192 {
193 bc_vec_string(&v, strlen(home), home);
194 bc_vec_concat(&v, bc_history_editrc);
195 }
196
197 h->hist = history_init();
198 if (BC_ERR(h->hist == NULL)) bc_vm_fatalError(BC_ERR_FATAL_ALLOC_ERR);
199
198 h->el = el_init(vm.name, stdin, stdout, stderr);
200 h->el = el_init(vm->name, stdin, stdout, stderr);
199 if (BC_ERR(h->el == NULL)) bc_vm_fatalError(BC_ERR_FATAL_ALLOC_ERR);
200
201 // I want history and a prompt.
202 history(h->hist, &bc_history_event, H_SETSIZE, 100);
203 history(h->hist, &bc_history_event, H_SETUNIQUE, 1);
204 el_set(h->el, EL_EDITOR, "emacs");
205 el_set(h->el, EL_HIST, history, h->hist);
206 el_set(h->el, EL_PROMPT, bc_history_promptFunc);

--- 43 unchanged lines hidden (view full) ---

250 {
251 free(bc_history_prompt);
252 bc_history_prompt = bc_vm_strdup(prompt);
253 }
254 }
255 else bc_history_prompt = bc_vm_strdup(prompt);
256 }
257
201 if (BC_ERR(h->el == NULL)) bc_vm_fatalError(BC_ERR_FATAL_ALLOC_ERR);
202
203 // I want history and a prompt.
204 history(h->hist, &bc_history_event, H_SETSIZE, 100);
205 history(h->hist, &bc_history_event, H_SETUNIQUE, 1);
206 el_set(h->el, EL_EDITOR, "emacs");
207 el_set(h->el, EL_HIST, history, h->hist);
208 el_set(h->el, EL_PROMPT, bc_history_promptFunc);

--- 43 unchanged lines hidden (view full) ---

252 {
253 free(bc_history_prompt);
254 bc_history_prompt = bc_vm_strdup(prompt);
255 }
256 }
257 else bc_history_prompt = bc_vm_strdup(prompt);
258 }
259
260 bc_history_use_prompt = true;
261
262 line = NULL;
263 len = -1;
264 errno = EINTR;
265
258 // Get the line.
266 // Get the line.
259 line = el_gets(h->el, &len);
267 while (line == NULL && len == -1 && errno == EINTR)
268 {
269 line = el_gets(h->el, &len);
270 bc_history_use_prompt = false;
271 }
260
261 // If there is no line...
262 if (BC_ERR(line == NULL))
263 {
264 // If this is true, there was an error. Otherwise, it's just EOF.
265 if (len == -1)
266 {
267 if (errno == ENOMEM) bc_err(BC_ERR_FATAL_ALLOC_ERR);
268 bc_err(BC_ERR_FATAL_IO_ERR);
269 }
270 else
271 {
272
273 // If there is no line...
274 if (BC_ERR(line == NULL))
275 {
276 // If this is true, there was an error. Otherwise, it's just EOF.
277 if (len == -1)
278 {
279 if (errno == ENOMEM) bc_err(BC_ERR_FATAL_ALLOC_ERR);
280 bc_err(BC_ERR_FATAL_IO_ERR);
281 }
282 else
283 {
272 bc_file_printf(&vm.fout, "\n");
284 bc_file_printf(&vm->fout, "\n");
273 s = BC_STATUS_EOF;
274 }
275 }
276 // If there is a line...
277 else
278 {
279 bc_vec_string(vec, strlen(line), line);
280

--- 82 unchanged lines hidden (view full) ---

363
364 bc_vec_expand(vec, len + 2);
365
366 bc_vec_string(vec, len, h->line);
367 bc_vec_concat(vec, "\n");
368 }
369 else if (h->line == NULL)
370 {
285 s = BC_STATUS_EOF;
286 }
287 }
288 // If there is a line...
289 else
290 {
291 bc_vec_string(vec, strlen(line), line);
292

--- 82 unchanged lines hidden (view full) ---

375
376 bc_vec_expand(vec, len + 2);
377
378 bc_vec_string(vec, len, h->line);
379 bc_vec_concat(vec, "\n");
380 }
381 else if (h->line == NULL)
382 {
371 bc_file_printf(&vm.fout, "%s\n", "^D");
383 bc_file_printf(&vm->fout, "%s\n", "^D");
372 s = BC_STATUS_EOF;
373 }
374 else bc_vec_string(vec, 1, "\n");
375
376end:
377
378 bc_history_inlinelib = 0;
379

--- 181 unchanged lines hidden (view full) ---

561 uint32_t cp;
562 size_t beg = pos;
563 size_t len = bc_history_codePoint(buf + pos, buf_len - pos, &cp);
564
565 if (bc_history_comboChar(cp))
566 {
567 BC_UNREACHABLE
568
384 s = BC_STATUS_EOF;
385 }
386 else bc_vec_string(vec, 1, "\n");
387
388end:
389
390 bc_history_inlinelib = 0;
391

--- 181 unchanged lines hidden (view full) ---

573 uint32_t cp;
574 size_t beg = pos;
575 size_t len = bc_history_codePoint(buf + pos, buf_len - pos, &cp);
576
577 if (bc_history_comboChar(cp))
578 {
579 BC_UNREACHABLE
580
581#if !BC_CLANG
569 if (col_len != NULL) *col_len = 0;
570
571 return 0;
582 if (col_len != NULL) *col_len = 0;
583
584 return 0;
585#endif // !BC_CLANG
572 }
573
574 // Store the width of the character on screen.
575 if (col_len != NULL) *col_len = bc_history_wchar(cp) ? 2 : 1;
576
577 pos += len;
578
579 // Find the first non-combining character.

--- 32 unchanged lines hidden (view full) ---

612 // The original linenoise-mob had an extra parameter col_len, like
613 // bc_history_nextLen(), which, if not NULL, was set in this if
614 // statement. However, we always passed NULL, so just skip that.
615 if (!bc_history_comboChar(cp)) return end - pos;
616 }
617
618 BC_UNREACHABLE
619
586 }
587
588 // Store the width of the character on screen.
589 if (col_len != NULL) *col_len = bc_history_wchar(cp) ? 2 : 1;
590
591 pos += len;
592
593 // Find the first non-combining character.

--- 32 unchanged lines hidden (view full) ---

626 // The original linenoise-mob had an extra parameter col_len, like
627 // bc_history_nextLen(), which, if not NULL, was set in this if
628 // statement. However, we always passed NULL, so just skip that.
629 if (!bc_history_comboChar(cp)) return end - pos;
630 }
631
632 BC_UNREACHABLE
633
634#if !BC_CLANG
620 return 0;
635 return 0;
636#endif // BC_CLANG
621}
622
623/**
624 * Reads @a n characters from stdin.
625 * @param buf The buffer to read into. The caller is responsible for making
626 * sure this is big enough for @a n.
627 * @param n The number of characters to read.
628 * @return The number of characters read or less than 0 on error.

--- 36 unchanged lines hidden (view full) ---

665 * @param cp An out parameter for the codepoint.
666 * @param nread An out parameter for the number of bytes read.
667 * @return BC_STATUS_EOF or BC_STATUS_SUCCESS.
668 */
669static BcStatus
670bc_history_readCode(char* buf, size_t buf_len, uint32_t* cp, size_t* nread)
671{
672 ssize_t n;
637}
638
639/**
640 * Reads @a n characters from stdin.
641 * @param buf The buffer to read into. The caller is responsible for making
642 * sure this is big enough for @a n.
643 * @param n The number of characters to read.
644 * @return The number of characters read or less than 0 on error.

--- 36 unchanged lines hidden (view full) ---

681 * @param cp An out parameter for the codepoint.
682 * @param nread An out parameter for the number of bytes read.
683 * @return BC_STATUS_EOF or BC_STATUS_SUCCESS.
684 */
685static BcStatus
686bc_history_readCode(char* buf, size_t buf_len, uint32_t* cp, size_t* nread)
687{
688 ssize_t n;
689 uchar byte;
673
674 assert(buf_len >= 1);
675
676 BC_SIG_LOCK;
677
678 // Read a byte.
679 n = bc_history_read(buf, 1);
680
681 BC_SIG_UNLOCK;
682
683 if (BC_ERR(n <= 0)) goto err;
684
685 // Get the byte.
690
691 assert(buf_len >= 1);
692
693 BC_SIG_LOCK;
694
695 // Read a byte.
696 n = bc_history_read(buf, 1);
697
698 BC_SIG_UNLOCK;
699
700 if (BC_ERR(n <= 0)) goto err;
701
702 // Get the byte.
686 uchar byte = ((uchar*) buf)[0];
703 byte = ((uchar*) buf)[0];
687
688 // Once again, this is the UTF-8 decoding algorithm, but it has reads
689 // instead of actual decoding.
690 if ((byte & 0x80) != 0)
691 {
692 if ((byte & 0xE0) == 0xC0)
693 {
694 assert(buf_len >= 2);

--- 198 unchanged lines hidden (view full) ---

893 char buf[BC_HIST_SEQ_SIZE];
894 char* ptr;
895 char* ptr2;
896 size_t cols, rows, i;
897
898 BC_SIG_ASSERT_LOCKED;
899
900 // Report cursor location.
704
705 // Once again, this is the UTF-8 decoding algorithm, but it has reads
706 // instead of actual decoding.
707 if ((byte & 0x80) != 0)
708 {
709 if ((byte & 0xE0) == 0xC0)
710 {
711 assert(buf_len >= 2);

--- 198 unchanged lines hidden (view full) ---

910 char buf[BC_HIST_SEQ_SIZE];
911 char* ptr;
912 char* ptr2;
913 size_t cols, rows, i;
914
915 BC_SIG_ASSERT_LOCKED;
916
917 // Report cursor location.
901 bc_file_write(&vm.fout, bc_flush_none, "\x1b[6n", 4);
902 bc_file_flush(&vm.fout, bc_flush_none);
918 bc_file_write(&vm->fout, bc_flush_none, "\x1b[6n", 4);
919 bc_file_flush(&vm->fout, bc_flush_none);
903
904 // Read the response: ESC [ rows ; cols R.
905 for (i = 0; i < sizeof(buf) - 1; ++i)
906 {
907 if (bc_history_read(buf + i, 1) != 1 || buf[i] == 'R') break;
908 }
909
910 buf[i] = '\0';

--- 26 unchanged lines hidden (view full) ---

937bc_history_columns(void)
938{
939
940#ifndef _WIN32
941
942 struct winsize ws;
943 int ret;
944
920
921 // Read the response: ESC [ rows ; cols R.
922 for (i = 0; i < sizeof(buf) - 1; ++i)
923 {
924 if (bc_history_read(buf + i, 1) != 1 || buf[i] == 'R') break;
925 }
926
927 buf[i] = '\0';

--- 26 unchanged lines hidden (view full) ---

954bc_history_columns(void)
955{
956
957#ifndef _WIN32
958
959 struct winsize ws;
960 int ret;
961
945 ret = ioctl(vm.fout.fd, TIOCGWINSZ, &ws);
962 ret = ioctl(vm->fout.fd, TIOCGWINSZ, &ws);
946
947 if (BC_ERR(ret == -1 || !ws.ws_col))
948 {
949 // Calling ioctl() failed. Try to query the terminal itself.
950 size_t start, cols;
951
952 // Get the initial position so we can restore it later.
953 start = bc_history_cursorPos();
954 if (BC_ERR(start == SIZE_MAX)) return BC_HIST_DEF_COLS;
955
956 // Go to right margin and get position.
963
964 if (BC_ERR(ret == -1 || !ws.ws_col))
965 {
966 // Calling ioctl() failed. Try to query the terminal itself.
967 size_t start, cols;
968
969 // Get the initial position so we can restore it later.
970 start = bc_history_cursorPos();
971 if (BC_ERR(start == SIZE_MAX)) return BC_HIST_DEF_COLS;
972
973 // Go to right margin and get position.
957 bc_file_write(&vm.fout, bc_flush_none, "\x1b[999C", 6);
958 bc_file_flush(&vm.fout, bc_flush_none);
974 bc_file_write(&vm->fout, bc_flush_none, "\x1b[999C", 6);
975 bc_file_flush(&vm->fout, bc_flush_none);
959 cols = bc_history_cursorPos();
960 if (BC_ERR(cols == SIZE_MAX)) return BC_HIST_DEF_COLS;
961
962 // Restore position.
963 if (cols > start)
964 {
976 cols = bc_history_cursorPos();
977 if (BC_ERR(cols == SIZE_MAX)) return BC_HIST_DEF_COLS;
978
979 // Restore position.
980 if (cols > start)
981 {
965 bc_file_printf(&vm.fout, "\x1b[%zuD", cols - start);
966 bc_file_flush(&vm.fout, bc_flush_none);
982 bc_file_printf(&vm->fout, "\x1b[%zuD", cols - start);
983 bc_file_flush(&vm->fout, bc_flush_none);
967 }
968
969 return cols;
970 }
971
972 return ws.ws_col;
973
974#else // _WIN32

--- 41 unchanged lines hidden (view full) ---

1016static void
1017bc_history_refresh(BcHistory* h)
1018{
1019 char* buf = h->buf.v;
1020 size_t colpos, len = BC_HIST_BUF_LEN(h), pos = h->pos, extras_len = 0;
1021
1022 BC_SIG_ASSERT_LOCKED;
1023
984 }
985
986 return cols;
987 }
988
989 return ws.ws_col;
990
991#else // _WIN32

--- 41 unchanged lines hidden (view full) ---

1033static void
1034bc_history_refresh(BcHistory* h)
1035{
1036 char* buf = h->buf.v;
1037 size_t colpos, len = BC_HIST_BUF_LEN(h), pos = h->pos, extras_len = 0;
1038
1039 BC_SIG_ASSERT_LOCKED;
1040
1024 bc_file_flush(&vm.fout, bc_flush_none);
1041 bc_file_flush(&vm->fout, bc_flush_none);
1025
1026 // Get to the prompt column position from the left.
1027 while (h->pcol + bc_history_colPos(buf, len, pos) >= h->cols)
1028 {
1029 size_t chlen = bc_history_nextLen(buf, len, 0, NULL);
1030
1031 buf += chlen;
1032 len -= chlen;
1033 pos -= chlen;
1034 }
1035
1036 // Get to the prompt column position from the right.
1037 while (h->pcol + bc_history_colPos(buf, len, len) > h->cols)
1038 {
1039 len -= bc_history_prevLen(buf, len);
1040 }
1041
1042 // Cursor to left edge.
1042
1043 // Get to the prompt column position from the left.
1044 while (h->pcol + bc_history_colPos(buf, len, pos) >= h->cols)
1045 {
1046 size_t chlen = bc_history_nextLen(buf, len, 0, NULL);
1047
1048 buf += chlen;
1049 len -= chlen;
1050 pos -= chlen;
1051 }
1052
1053 // Get to the prompt column position from the right.
1054 while (h->pcol + bc_history_colPos(buf, len, len) > h->cols)
1055 {
1056 len -= bc_history_prevLen(buf, len);
1057 }
1058
1059 // Cursor to left edge.
1043 bc_file_write(&vm.fout, bc_flush_none, "\r", 1);
1060 bc_file_write(&vm->fout, bc_flush_none, "\r", 1);
1044
1045 // Take the extra stuff into account. This is where history makes sure to
1046 // preserve stuff that was printed without a newline.
1047 if (h->extras.len > 1)
1048 {
1049 extras_len = h->extras.len - 1;
1050
1051 bc_vec_grow(&h->buf, extras_len);
1052
1053 len += extras_len;
1054 pos += extras_len;
1055
1061
1062 // Take the extra stuff into account. This is where history makes sure to
1063 // preserve stuff that was printed without a newline.
1064 if (h->extras.len > 1)
1065 {
1066 extras_len = h->extras.len - 1;
1067
1068 bc_vec_grow(&h->buf, extras_len);
1069
1070 len += extras_len;
1071 pos += extras_len;
1072
1056 bc_file_write(&vm.fout, bc_flush_none, h->extras.v, extras_len);
1073 bc_file_write(&vm->fout, bc_flush_none, h->extras.v, extras_len);
1057 }
1058
1059 // Write the prompt, if desired.
1074 }
1075
1076 // Write the prompt, if desired.
1060 if (BC_PROMPT) bc_file_write(&vm.fout, bc_flush_none, h->prompt, h->plen);
1077 if (BC_PROMPT) bc_file_write(&vm->fout, bc_flush_none, h->prompt, h->plen);
1061
1078
1062 bc_file_write(&vm.fout, bc_flush_none, h->buf.v, len - extras_len);
1079 bc_file_write(&vm->fout, bc_flush_none, h->buf.v, len - extras_len);
1063
1064 // Erase to right.
1080
1081 // Erase to right.
1065 bc_file_write(&vm.fout, bc_flush_none, "\x1b[0K", 4);
1082 bc_file_write(&vm->fout, bc_flush_none, "\x1b[0K", 4);
1066
1067 // We need to be sure to grow this.
1068 if (pos >= h->buf.len - extras_len) bc_vec_grow(&h->buf, pos + extras_len);
1069
1070 // Move cursor to original position. Do NOT move the putchar of '\r' to the
1071 // printf with colpos. That causes a bug where the cursor will go to the end
1072 // of the line when there is no prompt.
1083
1084 // We need to be sure to grow this.
1085 if (pos >= h->buf.len - extras_len) bc_vec_grow(&h->buf, pos + extras_len);
1086
1087 // Move cursor to original position. Do NOT move the putchar of '\r' to the
1088 // printf with colpos. That causes a bug where the cursor will go to the end
1089 // of the line when there is no prompt.
1073 bc_file_putchar(&vm.fout, bc_flush_none, '\r');
1090 bc_file_putchar(&vm->fout, bc_flush_none, '\r');
1074 colpos = bc_history_colPos(h->buf.v, len - extras_len, pos) + h->pcol;
1075
1076 // Set the cursor position again.
1091 colpos = bc_history_colPos(h->buf.v, len - extras_len, pos) + h->pcol;
1092
1093 // Set the cursor position again.
1077 if (colpos) bc_file_printf(&vm.fout, "\x1b[%zuC", colpos);
1094 if (colpos) bc_file_printf(&vm->fout, "\x1b[%zuC", colpos);
1078
1095
1079 bc_file_flush(&vm.fout, bc_flush_none);
1096 bc_file_flush(&vm->fout, bc_flush_none);
1080}
1081
1082/**
1083 * Inserts the character(s) 'c' at cursor current position.
1084 * @param h The history data.
1085 * @param cbuf The character buffer to copy from.
1086 * @param clen The number of characters to copy.
1087 */

--- 21 unchanged lines hidden (view full) ---

1109 len = BC_HIST_BUF_LEN(h) + h->extras.len - 1;
1110 colpos = bc_history_promptColLen(h->prompt, h->plen);
1111 colpos += bc_history_colPos(h->buf.v, len, len);
1112
1113 // Do we have the trivial case?
1114 if (colpos < h->cols)
1115 {
1116 // Avoid a full update of the line in the trivial case.
1097}
1098
1099/**
1100 * Inserts the character(s) 'c' at cursor current position.
1101 * @param h The history data.
1102 * @param cbuf The character buffer to copy from.
1103 * @param clen The number of characters to copy.
1104 */

--- 21 unchanged lines hidden (view full) ---

1126 len = BC_HIST_BUF_LEN(h) + h->extras.len - 1;
1127 colpos = bc_history_promptColLen(h->prompt, h->plen);
1128 colpos += bc_history_colPos(h->buf.v, len, len);
1129
1130 // Do we have the trivial case?
1131 if (colpos < h->cols)
1132 {
1133 // Avoid a full update of the line in the trivial case.
1117 bc_file_write(&vm.fout, bc_flush_none, cbuf, clen);
1118 bc_file_flush(&vm.fout, bc_flush_none);
1134 bc_file_write(&vm->fout, bc_flush_none, cbuf, clen);
1135 bc_file_flush(&vm->fout, bc_flush_none);
1119 }
1120 else bc_history_refresh(h);
1121 }
1122 else
1123 {
1124 // Amount that we need to move.
1125 size_t amt = BC_HIST_BUF_LEN(h) - h->pos;
1126

--- 318 unchanged lines hidden (view full) ---

1445static void
1446bc_history_swap(BcHistory* h)
1447{
1448 size_t pcl, ncl;
1449 char auxb[5];
1450
1451 BC_SIG_ASSERT_LOCKED;
1452
1136 }
1137 else bc_history_refresh(h);
1138 }
1139 else
1140 {
1141 // Amount that we need to move.
1142 size_t amt = BC_HIST_BUF_LEN(h) - h->pos;
1143

--- 318 unchanged lines hidden (view full) ---

1462static void
1463bc_history_swap(BcHistory* h)
1464{
1465 size_t pcl, ncl;
1466 char auxb[5];
1467
1468 BC_SIG_ASSERT_LOCKED;
1469
1470 // If there are no characters, skip.
1471 if (!h->pos) return;
1472
1453 // Get the length of the previous and next characters.
1454 pcl = bc_history_prevLen(h->buf.v, h->pos);
1455 ncl = bc_history_nextLen(h->buf.v, BC_HIST_BUF_LEN(h), h->pos, NULL);
1456
1457 // To perform a swap we need:
1458 // * Nonzero char length to the left.
1459 // * To not be at the end of the line.
1460 if (pcl && h->pos != BC_HIST_BUF_LEN(h) && pcl < 5 && ncl < 5)

--- 240 unchanged lines hidden (view full) ---

1701/**
1702 * Adds an empty line to the history. This is separate from bc_history_add()
1703 * because we don't want it allocating.
1704 * @param h The history data.
1705 */
1706static void
1707bc_history_add_empty(BcHistory* h)
1708{
1473 // Get the length of the previous and next characters.
1474 pcl = bc_history_prevLen(h->buf.v, h->pos);
1475 ncl = bc_history_nextLen(h->buf.v, BC_HIST_BUF_LEN(h), h->pos, NULL);
1476
1477 // To perform a swap we need:
1478 // * Nonzero char length to the left.
1479 // * To not be at the end of the line.
1480 if (pcl && h->pos != BC_HIST_BUF_LEN(h) && pcl < 5 && ncl < 5)

--- 240 unchanged lines hidden (view full) ---

1721/**
1722 * Adds an empty line to the history. This is separate from bc_history_add()
1723 * because we don't want it allocating.
1724 * @param h The history data.
1725 */
1726static void
1727bc_history_add_empty(BcHistory* h)
1728{
1709 BC_SIG_ASSERT_LOCKED;
1710
1711 const char* line = "";
1712
1729 const char* line = "";
1730
1731 BC_SIG_ASSERT_LOCKED;
1732
1713 // If there is something already there...
1714 if (h->history.len)
1715 {
1716 // Get the previous.
1717 char* s = *((char**) bc_vec_item_rev(&h->history, 0));
1718
1719 // Check for, and discard, duplicates.
1720 if (!s[0]) return;

--- 42 unchanged lines hidden (view full) ---

1763 bc_vec_concat(&h->buf, str);
1764
1765 h->pos = BC_HIST_BUF_LEN(h);
1766 bc_history_refresh(h);
1767
1768 // Pop the string.
1769 bc_vec_npop(&h->buf, sizeof(str));
1770 bc_vec_pushByte(&h->buf, '\0');
1733 // If there is something already there...
1734 if (h->history.len)
1735 {
1736 // Get the previous.
1737 char* s = *((char**) bc_vec_item_rev(&h->history, 0));
1738
1739 // Check for, and discard, duplicates.
1740 if (!s[0]) return;

--- 42 unchanged lines hidden (view full) ---

1783 bc_vec_concat(&h->buf, str);
1784
1785 h->pos = BC_HIST_BUF_LEN(h);
1786 bc_history_refresh(h);
1787
1788 // Pop the string.
1789 bc_vec_npop(&h->buf, sizeof(str));
1790 bc_vec_pushByte(&h->buf, '\0');
1791 h->pos = 0;
1771
1772 if (c != BC_ACTION_CTRL_C && c != BC_ACTION_CTRL_D)
1773 {
1774 // We sometimes want to print a newline; for the times we don't; it's
1775 // because newlines are taken care of elsewhere.
1792
1793 if (c != BC_ACTION_CTRL_C && c != BC_ACTION_CTRL_D)
1794 {
1795 // We sometimes want to print a newline; for the times we don't; it's
1796 // because newlines are taken care of elsewhere.
1776 bc_file_write(&vm.fout, bc_flush_none, newline, sizeof(newline) - 1);
1797 bc_file_write(&vm->fout, bc_flush_none, newline, sizeof(newline) - 1);
1777 bc_history_refresh(h);
1778 }
1779}
1780
1781/**
1782 * Edits a line of history. This function is the core of the line editing
1783 * capability of bc history. It expects 'fd' to be already in "raw mode" so that
1784 * every key pressed will be returned ASAP to read().

--- 6 unchanged lines hidden (view full) ---

1791{
1792 BC_SIG_LOCK;
1793
1794 bc_history_reset(h);
1795
1796 // Don't write the saved output the first time. This is because it has
1797 // already been written to output. In other words, don't uncomment the
1798 // line below or add anything like it.
1798 bc_history_refresh(h);
1799 }
1800}
1801
1802/**
1803 * Edits a line of history. This function is the core of the line editing
1804 * capability of bc history. It expects 'fd' to be already in "raw mode" so that
1805 * every key pressed will be returned ASAP to read().

--- 6 unchanged lines hidden (view full) ---

1812{
1813 BC_SIG_LOCK;
1814
1815 bc_history_reset(h);
1816
1817 // Don't write the saved output the first time. This is because it has
1818 // already been written to output. In other words, don't uncomment the
1819 // line below or add anything like it.
1799 // bc_file_write(&vm.fout, bc_flush_none, h->extras.v, h->extras.len - 1);
1820 // bc_file_write(&vm->fout, bc_flush_none, h->extras.v, h->extras.len - 1);
1800
1801 // Write the prompt if desired.
1802 if (BC_PROMPT)
1803 {
1804 h->prompt = prompt;
1805 h->plen = strlen(prompt);
1806 h->pcol = bc_history_promptColLen(prompt, h->plen);
1807
1821
1822 // Write the prompt if desired.
1823 if (BC_PROMPT)
1824 {
1825 h->prompt = prompt;
1826 h->plen = strlen(prompt);
1827 h->pcol = bc_history_promptColLen(prompt, h->plen);
1828
1808 bc_file_write(&vm.fout, bc_flush_none, prompt, h->plen);
1809 bc_file_flush(&vm.fout, bc_flush_none);
1829 bc_file_write(&vm->fout, bc_flush_none, prompt, h->plen);
1830 bc_file_flush(&vm->fout, bc_flush_none);
1810 }
1811
1812 // This is the input loop.
1813 for (;;)
1814 {
1815 BcStatus s;
1816 char cbuf[32];
1817 unsigned int c = 0;

--- 28 unchanged lines hidden (view full) ---

1846
1847 case BC_ACTION_CTRL_C:
1848 {
1849 bc_history_printCtrl(h, c);
1850
1851 // Quit if the user wants it.
1852 if (!BC_SIGINT)
1853 {
1831 }
1832
1833 // This is the input loop.
1834 for (;;)
1835 {
1836 BcStatus s;
1837 char cbuf[32];
1838 unsigned int c = 0;

--- 28 unchanged lines hidden (view full) ---

1867
1868 case BC_ACTION_CTRL_C:
1869 {
1870 bc_history_printCtrl(h, c);
1871
1872 // Quit if the user wants it.
1873 if (!BC_SIGINT)
1874 {
1854 vm.status = BC_STATUS_QUIT;
1875 vm->status = BC_STATUS_QUIT;
1855 BC_SIG_UNLOCK;
1856 BC_JMP;
1857 }
1858
1859 // Print the ready message.
1876 BC_SIG_UNLOCK;
1877 BC_JMP;
1878 }
1879
1880 // Print the ready message.
1860 bc_file_write(&vm.fout, bc_flush_none, vm.sigmsg, vm.siglen);
1861 bc_file_write(&vm.fout, bc_flush_none, bc_program_ready_msg,
1881 bc_file_write(&vm->fout, bc_flush_none, vm->sigmsg, vm->siglen);
1882 bc_file_write(&vm->fout, bc_flush_none, bc_program_ready_msg,
1862 bc_program_ready_msg_len);
1863 bc_history_reset(h);
1864 bc_history_refresh(h);
1865
1866 break;
1867 }
1868
1869 case BC_ACTION_BACKSPACE:

--- 89 unchanged lines hidden (view full) ---

1959 {
1960 bc_history_edit_end(h);
1961 break;
1962 }
1963
1964 // Clear screen.
1965 case BC_ACTION_CTRL_L:
1966 {
1883 bc_program_ready_msg_len);
1884 bc_history_reset(h);
1885 bc_history_refresh(h);
1886
1887 break;
1888 }
1889
1890 case BC_ACTION_BACKSPACE:

--- 89 unchanged lines hidden (view full) ---

1980 {
1981 bc_history_edit_end(h);
1982 break;
1983 }
1984
1985 // Clear screen.
1986 case BC_ACTION_CTRL_L:
1987 {
1967 bc_file_write(&vm.fout, bc_flush_none, "\x1b[H\x1b[2J", 7);
1988 bc_file_write(&vm->fout, bc_flush_none, "\x1b[H\x1b[2J", 7);
1968 bc_history_refresh(h);
1969 break;
1970 }
1971
1972 // Delete previous word.
1973 case BC_ACTION_CTRL_W:
1974 {
1975 bc_history_edit_deletePrevWord(h);

--- 11 unchanged lines hidden (view full) ---

1987#ifndef _WIN32
1988 if (c == BC_ACTION_CTRL_Z) bc_history_raise(h, SIGTSTP);
1989 if (c == BC_ACTION_CTRL_S) bc_history_raise(h, SIGSTOP);
1990 if (c == BC_ACTION_CTRL_BSLASH)
1991 {
1992 bc_history_raise(h, SIGQUIT);
1993 }
1994#else // _WIN32
1989 bc_history_refresh(h);
1990 break;
1991 }
1992
1993 // Delete previous word.
1994 case BC_ACTION_CTRL_W:
1995 {
1996 bc_history_edit_deletePrevWord(h);

--- 11 unchanged lines hidden (view full) ---

2008#ifndef _WIN32
2009 if (c == BC_ACTION_CTRL_Z) bc_history_raise(h, SIGTSTP);
2010 if (c == BC_ACTION_CTRL_S) bc_history_raise(h, SIGSTOP);
2011 if (c == BC_ACTION_CTRL_BSLASH)
2012 {
2013 bc_history_raise(h, SIGQUIT);
2014 }
2015#else // _WIN32
1995 vm.status = BC_STATUS_QUIT;
2016 vm->status = BC_STATUS_QUIT;
1996 BC_SIG_UNLOCK;
1997 BC_JMP;
1998#endif // _WIN32
1999 }
2000 // Otherwise, just insert.
2001 else bc_history_edit_insert(h, cbuf, nread);
2002 break;
2003 }

--- 23 unchanged lines hidden (view full) ---

2027}
2028
2029BcStatus
2030bc_history_line(BcHistory* h, BcVec* vec, const char* prompt)
2031{
2032 BcStatus s;
2033 char* line;
2034
2017 BC_SIG_UNLOCK;
2018 BC_JMP;
2019#endif // _WIN32
2020 }
2021 // Otherwise, just insert.
2022 else bc_history_edit_insert(h, cbuf, nread);
2023 break;
2024 }

--- 23 unchanged lines hidden (view full) ---

2048}
2049
2050BcStatus
2051bc_history_line(BcHistory* h, BcVec* vec, const char* prompt)
2052{
2053 BcStatus s;
2054 char* line;
2055
2035 assert(vm.fout.len == 0);
2056 assert(vm->fout.len == 0);
2036
2037 bc_history_enableRaw(h);
2038
2039 do
2040 {
2041 // Do the edit.
2042 s = bc_history_edit(h, prompt);
2043
2044 // Print a newline and flush.
2057
2058 bc_history_enableRaw(h);
2059
2060 do
2061 {
2062 // Do the edit.
2063 s = bc_history_edit(h, prompt);
2064
2065 // Print a newline and flush.
2045 bc_file_write(&vm.fout, bc_flush_none, "\n", 1);
2046 bc_file_flush(&vm.fout, bc_flush_none);
2066 bc_file_write(&vm->fout, bc_flush_none, "\n", 1);
2067 bc_file_flush(&vm->fout, bc_flush_none);
2047
2048 BC_SIG_LOCK;
2049
2050 // If we actually have data...
2051 if (h->buf.v[0])
2052 {
2053 // Duplicate it.
2054 line = bc_vm_strdup(h->buf.v);

--- 152 unchanged lines hidden (view full) ---

2207 quit[sizeof(quit) - 1] = c;
2208 if (!memcmp(quit, "quit", sizeof(quit))) break;
2209
2210 bc_vm_printf("'%c' %lu (type quit to exit)\n", isprint(c) ? c : '?',
2211 (unsigned long) c);
2212
2213 // Go left edge manually, we are in raw mode.
2214 bc_vm_putchar('\r', bc_flush_none);
2068
2069 BC_SIG_LOCK;
2070
2071 // If we actually have data...
2072 if (h->buf.v[0])
2073 {
2074 // Duplicate it.
2075 line = bc_vm_strdup(h->buf.v);

--- 152 unchanged lines hidden (view full) ---

2228 quit[sizeof(quit) - 1] = c;
2229 if (!memcmp(quit, "quit", sizeof(quit))) break;
2230
2231 bc_vm_printf("'%c' %lu (type quit to exit)\n", isprint(c) ? c : '?',
2232 (unsigned long) c);
2233
2234 // Go left edge manually, we are in raw mode.
2235 bc_vm_putchar('\r', bc_flush_none);
2215 bc_file_flush(&vm.fout, bc_flush_none);
2236 bc_file_flush(&vm->fout, bc_flush_none);
2216 }
2217
2218 bc_history_disableRaw(h);
2219}
2220#endif // BC_DEBUG_CODE
2221
2222#endif // BC_ENABLE_HISTORY
2223
2224#endif // BC_ENABLE_READLINE
2225
2226#endif // BC_ENABLE_EDITLINE
2237 }
2238
2239 bc_history_disableRaw(h);
2240}
2241#endif // BC_DEBUG_CODE
2242
2243#endif // BC_ENABLE_HISTORY
2244
2245#endif // BC_ENABLE_READLINE
2246
2247#endif // BC_ENABLE_EDITLINE