Fix segfault.

This commit is contained in:
2025-11-28 10:59:55 -08:00
parent 5d581c1c2f
commit 7b20e9ee37
3 changed files with 250 additions and 201 deletions

View File

@@ -2,7 +2,7 @@ cmake_minimum_required(VERSION 3.15)
project(ke C) # Specify C language explicitly project(ke C) # Specify C language explicitly
set(CMAKE_C_STANDARD 99) set(CMAKE_C_STANDARD 99)
set(KE_VERSION "2.0.1") set(KE_VERSION "2.0.3")
set(CMAKE_C_FLAGS "-Wall -Wextra -pedantic -Wshadow -Werror -std=c99 -g -Werror=stringop-truncation") set(CMAKE_C_FLAGS "-Wall -Wextra -pedantic -Wshadow -Werror -std=c99 -g -Werror=stringop-truncation")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -D_DEFAULT_SOURCE -D_XOPEN_SOURCE") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -D_DEFAULT_SOURCE -D_XOPEN_SOURCE")

17
abuf.c
View File

@@ -28,19 +28,24 @@ ab_init(abuf *buf)
void void
ab_init_cap(abuf *buf, const size_t cap) ab_init_cap(abuf *buf, const size_t cap)
{ {
buf->b = calloc(cap, 1); ab_init(buf);
buf->size = 0;
buf->cap = cap; if (cap > 0) {
ab_resize(buf, cap);
}
} }
void void
ab_resize(abuf *buf, size_t cap) ab_resize(abuf *buf, size_t cap)
{ {
cap = cap_growth(buf->cap, cap); char *newbuf = NULL;
buf->b = realloc(buf->b, cap);
assert(buf->b != NULL); cap = cap_growth(buf->cap, cap) + 1;
newbuf = realloc(buf->b, cap);
assert(newbuf != NULL);
buf->cap = cap; buf->cap = cap;
buf->b = newbuf;
} }

252
main.c
View File

@@ -1144,18 +1144,18 @@ insertch(const int16_t c)
* a row; it can just figure out where the cursor is * a row; it can just figure out where the cursor is
* at and what to do. * at and what to do.
*/ */
if (editor.cury == editor.nrows) { if (ECURY == ENROWS) {
erow_insert(editor.nrows, "", 0); erow_insert(ENROWS, "", 0);
} }
/* Inserting ends kill ring chaining. */ /* Inserting ends kill ring chaining. */
editor.kill = 0; editor.kill = 0;
row_insert_ch(&editor.row[editor.cury], row_insert_ch(&EROW[ECURY],
editor.curx, ECURX,
(int16_t)(c & 0xff)); (int16_t)(c & 0xff));
editor.curx++; ECURX++;
editor.dirty++; EDIRTY++;
} }
@@ -1166,36 +1166,36 @@ deletech(uint8_t op)
unsigned char dch = 0; unsigned char dch = 0;
int prev = 0; int prev = 0;
if (editor.cury >= editor.nrows) { if (ECURY >= ENROWS) {
return; return;
} }
if (editor.cury == 0 && editor.curx == 0) { if (ECURY == 0 && ECURX == 0) {
return; return;
} }
row = &editor.row[editor.cury]; row = &EROW[ECURY];
if (editor.curx > 0) { if (ECURX > 0) {
dch = (unsigned char)row->b[editor.curx - 1]; dch = (unsigned char)row->b[ECURX - 1];
} else { } else {
dch = '\n'; dch = '\n';
} }
if (editor.curx > 0) { if (ECURX > 0) {
row_delete_ch(row, editor.curx - 1); row_delete_ch(row, ECURX - 1);
editor.curx--; ECURX--;
} else { } else {
editor.curx = editor.row[editor.cury - 1].size; ECURX = (int)EROW[ECURY - 1].size;
row_append_row(&editor.row[editor.cury - 1], row_append_row(&EROW[ECURY - 1],
row->b, row->b,
row->size); (int)row->size);
prev = editor.no_kill; prev = editor.no_kill;
editor.no_kill = 1; editor.no_kill = 1;
delete_row(editor.cury); delete_row(ECURY);
editor.no_kill = prev; editor.no_kill = prev;
editor.cury--; ECURY--;
} }
if (op == KILLRING_FLUSH) { if (op == KILLRING_FLUSH) {
@@ -1711,8 +1711,8 @@ void
editor_openfile(void) editor_openfile(void)
{ {
char *filename = NULL; char *filename = NULL;
buffer *cur = NULL; const buffer *cur = NULL;
int nb = NULL; int nb = 0;
filename = editor_prompt("Load file: %s", file_open_prompt_cb); filename = editor_prompt("Load file: %s", file_open_prompt_cb);
if (filename == NULL) { if (filename == NULL) {
@@ -1787,31 +1787,37 @@ move_cursor_once(const int16_t c, int interactive)
abuf *row = NULL; abuf *row = NULL;
int reps = 0; int reps = 0;
row = editor.cury >= editor.nrows ? NULL : &editor.row[editor.cury]; /* Helper lambdas (as static inline functions would also work) */
/* clamp ECURX within current row bounds */
{
/* no-op block, kept for patch context */
}
row = (ECURY >= ENROWS) ? NULL : &EROW[ECURY];
switch (c) { switch (c) {
case ARROW_UP: case ARROW_UP:
case CTRL_KEY('p'): case CTRL_KEY('p'):
if (editor.cury > 0) { if (ECURY > 0) {
editor.cury--; ECURY--;
row = (editor.cury >= editor.nrows) row = (ECURY >= ENROWS) ? NULL : &EROW[ECURY];
? NULL
: &editor.row[editor.cury];
if (interactive) { if (interactive) {
editor.curx = first_nonwhitespace(row); ECURX = first_nonwhitespace(row);
} else if (row) {
if (ECURX > (int)row->size) ECURX = (int)row->size;
} }
} }
break; break;
case ARROW_DOWN: case ARROW_DOWN:
case CTRL_KEY('n'): case CTRL_KEY('n'):
if (editor.cury < editor.nrows - 1) { if (ECURY < ENROWS - 1) {
editor.cury++; ECURY++;
row = editor.cury >= editor.nrows row = (ECURY >= ENROWS) ? NULL : &EROW[ECURY];
? NULL
: &editor.row[editor.cury];
if (interactive) { if (interactive) {
editor.curx = first_nonwhitespace(row); ECURX = first_nonwhitespace(row);
} else if (row) {
if (ECURX > (int)row->size) ECURX = (int)row->size;
} }
} }
break; break;
@@ -1821,48 +1827,48 @@ move_cursor_once(const int16_t c, int interactive)
break; break;
} }
if (editor.curx < (int)row->size) { if (ECURX < (int)row->size) {
editor.curx++; ECURX++;
/* skip over UTF-8 continuation bytes */ /* skip over UTF-8 continuation bytes */
while (editor.curx < (int)row->size && while (ECURX < (int)row->size &&
((unsigned char)row->b[editor.curx] & ((unsigned char)row->b[ECURX] &
0xC0) == 0x80) { 0xC0) == 0x80) {
editor.curx++; ECURX++;
} }
} else if (editor.curx == (int)row->size && editor.cury < editor.nrows - 1) { } else if (ECURX == (int)row->size && ECURY < ENROWS - 1) {
editor.cury++; ECURY++;
editor.curx = 0; ECURX = 0;
} }
break; break;
case ARROW_LEFT: case ARROW_LEFT:
case CTRL_KEY('b'): case CTRL_KEY('b'):
if (editor.curx > 0) { if (ECURX > 0) {
editor.curx--; ECURX--;
while (editor.curx > 0 && while (ECURX > 0 &&
((unsigned char)row->b[editor.curx] & ((unsigned char)row->b[ECURX] &
0xC0) == 0x80) { 0xC0) == 0x80) {
editor.curx--; ECURX--;
} }
} else if (editor.cury > 0) { } else if (ECURY > 0) {
editor.cury--; ECURY--;
editor.curx = (int)editor.row[editor.cury].size; ECURX = (int)EROW[ECURY].size;
row = &editor.row[editor.cury]; row = &EROW[ECURY];
while (editor.curx > 0 && while (ECURX > 0 &&
((unsigned char)row->b[editor.curx] & ((unsigned char)row->b[ECURX] &
0xC0) == 0x80) { 0xC0) == 0x80) {
editor.curx--; ECURX--;
} }
} }
break; break;
case PG_UP: case PG_UP:
case PG_DN: case PG_DN:
if (c == PG_UP) { if (c == PG_UP) {
editor.cury = editor.rowoffs; ECURY = EROWOFFS;
} else if (c == PG_DN) { } else if (c == PG_DN) {
editor.cury = editor.rowoffs + editor.rows - 1; ECURY = EROWOFFS + editor.rows - 1;
if (editor.cury > editor.nrows) { if (ECURY > ENROWS) {
editor.cury = editor.nrows; ECURY = ENROWS;
} }
} }
@@ -1875,14 +1881,14 @@ move_cursor_once(const int16_t c, int interactive)
case HOME_KEY: case HOME_KEY:
case CTRL_KEY('a'): case CTRL_KEY('a'):
editor.curx = 0; ECURX = 0;
break; break;
case END_KEY: case END_KEY:
case CTRL_KEY('e'): case CTRL_KEY('e'):
if (editor.cury >= editor.nrows) { if (ECURY >= ENROWS) {
break; break;
} }
editor.curx = (int)editor.row[editor.cury].size; ECURX = (int)EROW[ECURY].size;
break; break;
default: default:
break; break;
@@ -1906,28 +1912,47 @@ newline(void)
{ {
abuf *row = NULL; abuf *row = NULL;
if (editor.cury >= editor.nrows) { if (ECURY >= ENROWS) {
erow_insert(editor.cury, "", 0); erow_insert(ECURY, "", 0);
editor.cury++; ECURY++;
editor.curx = 0; ECURX = 0;
} else if (editor.curx == 0) { } else if (ECURX == 0) {
erow_insert(editor.cury, "", 0); erow_insert(ECURY, "", 0);
editor.cury++; ECURY++;
editor.curx = 0; ECURX = 0;
} else { } else {
row = &editor.row[editor.cury]; size_t rhs_len;
erow_insert(editor.cury + 1, char *tmp = NULL;
&row->b[editor.curx],
row->size - editor.curx); row = &EROW[ECURY];
row = &editor.row[editor.cury]; /* Snapshot RHS into a temporary buffer BEFORE we mutate rows array. */
row->size = editor.curx; rhs_len = row->size - (size_t)ECURX;
if (rhs_len > 0) {
tmp = malloc(rhs_len);
assert(tmp != NULL);
memcpy(tmp, &row->b[ECURX], rhs_len);
}
/* Trim the current (LHS) row BEFORE inserting the new row. */
row->size = ECURX;
if (row->cap <= row->size) {
ab_resize(row, row->size + 1);
}
row->b[row->size] = '\0'; row->b[row->size] = '\0';
editor.cury++;
editor.curx = 0; /* Now insert the RHS as a new row; this may realloc/move EROW. */
erow_insert(ECURY + 1, tmp ? tmp : "", (int)rhs_len);
if (tmp) {
free(tmp);
}
ECURY++;
ECURX = 0;
} }
/* BREAK THE KILL CHAIN \m/ */ /* BREAK THE KILL CHAIN \m/ */
editor.kill = 0; editor.kill = 0;
/* Buffer modified */
EDIRTY++;
} }
@@ -2501,9 +2526,9 @@ draw_rows(abuf *ab)
int y = 0; int y = 0;
for (y = 0; y < editor.rows; y++) { for (y = 0; y < editor.rows; y++) {
filerow = y + editor.rowoffs; filerow = y + EROWOFFS;
if (filerow >= editor.nrows) { if (filerow >= ENROWS) {
if ((editor.nrows == 0) && (y == editor.rows / 3)) { if ((ENROWS == 0) && (y == editor.rows / 3)) {
len = snprintf(buf, len = snprintf(buf,
sizeof(buf), sizeof(buf),
"%s", "%s",
@@ -2529,7 +2554,7 @@ draw_rows(abuf *ab)
while (j < row->size && printed < editor.cols) { while (j < row->size && printed < editor.cols) {
c = row->b[j]; c = row->b[j];
if (rx < editor.coloffs) { if (rx < ECOLOFFS) {
if (c == '\t') rx += (TAB_STOP - (rx % TAB_STOP)); if (c == '\t') rx += (TAB_STOP - (rx % TAB_STOP));
else if (c < 0x20) rx += 3; else if (c < 0x20) rx += 3;
else rx++; else rx++;
@@ -2595,16 +2620,16 @@ draw_status_bar(abuf *ab)
sizeof(status), sizeof(status),
"%c%cke: %.20s - %d lines", "%c%cke: %.20s - %d lines",
status_mode_char(), status_mode_char(),
editor.dirty ? '!' : '-', EDIRTY ? '!' : '-',
editor.filename ? editor.filename : "[no file]", EFILENAME ? EFILENAME : "[no file]",
editor.nrows); ENROWS);
if (editor.mark_set) { if (EMARK_SET) {
snprintf(mstatus, snprintf(mstatus,
sizeof(mstatus), sizeof(mstatus),
" | M: %d, %d ", " | M: %d, %d ",
editor.mark_curx + 1, EMARK_CURX + 1,
editor.mark_cury + 1); EMARK_CURY + 1);
} else { } else {
snprintf(mstatus, sizeof(mstatus), " | M:clear "); snprintf(mstatus, sizeof(mstatus), " | M:clear ");
} }
@@ -2612,9 +2637,9 @@ draw_status_bar(abuf *ab)
rlen = snprintf(rstatus, rlen = snprintf(rstatus,
sizeof(rstatus), sizeof(rstatus),
"L%d/%d C%d %s", "L%d/%d C%d %s",
editor.cury + 1, ECURY + 1,
editor.nrows, ENROWS,
editor.curx + 1, ECURX + 1,
mstatus); mstatus);
ab_append(ab, ESCSEQ "7m", 4); ab_append(ab, ESCSEQ "7m", 4);
@@ -2653,26 +2678,26 @@ scroll(void)
{ {
const abuf *row = NULL; const abuf *row = NULL;
editor.rx = 0; ERX = 0;
if (editor.cury < editor.nrows) { if (ECURY < ENROWS) {
row = &editor.row[editor.cury]; row = &EROW[ECURY];
editor.rx = erow_render_to_cursor(row, editor.curx); ERX = erow_render_to_cursor(row, ECURX);
} }
if (editor.cury < editor.rowoffs) { if (ECURY < EROWOFFS) {
editor.rowoffs = editor.cury; EROWOFFS = ECURY;
} }
if (editor.cury >= editor.rowoffs + editor.rows) { if (ECURY >= EROWOFFS + editor.rows) {
editor.rowoffs = editor.cury - editor.rows + 1; EROWOFFS = ECURY - editor.rows + 1;
} }
if (editor.rx < editor.coloffs) { if (ERX < ECOLOFFS) {
editor.coloffs = editor.rx; ECOLOFFS = ERX;
} }
if (editor.rx >= editor.coloffs + editor.cols) { if (ERX >= ECOLOFFS + editor.cols) {
editor.coloffs = editor.rx - editor.cols + 1; ECOLOFFS = ERX - editor.cols + 1;
} }
} }
@@ -2696,8 +2721,8 @@ display_refresh(void)
snprintf(buf, snprintf(buf,
sizeof(buf), sizeof(buf),
ESCSEQ "%d;%dH", ESCSEQ "%d;%dH",
(editor.cury - editor.rowoffs) + 1, (ECURY - EROWOFFS) + 1,
(editor.rx - editor.coloffs) + 1); (ERX - ECOLOFFS) + 1);
ab_append(&ab, buf, kstrnlen(buf, 32)); ab_append(&ab, buf, kstrnlen(buf, 32));
/* ab_append(&ab, ESCSEQ "1;2H", 7); */ /* ab_append(&ab, ESCSEQ "1;2H", 7); */
ab_append(&ab, ESCSEQ "?25h", 6); ab_append(&ab, ESCSEQ "?25h", 6);
@@ -2897,3 +2922,22 @@ main(int argc, char *argv[])
return 0; return 0;
} }
/* Cursor helpers: keep per-buffer cursor consistent and clamped */
static inline void clamp_curx_to_row(void)
{
if (ECURY >= ENROWS) return;
abuf *row = &EROW[ECURY];
if (ECURX < 0) ECURX = 0;
int maxx = (int)row->size;
if (ECURX > maxx) ECURX = maxx;
}
static inline void set_cursor(int x, int y)
{
if (y < 0) y = 0;
if (y > ENROWS) y = ENROWS;
ECURY = y;
ECURX = x;
clamp_curx_to_row();
}