]>
git.ipfire.org Git - thirdparty/util-linux.git/blob - lib/mbsedit.c
2 * SPDX-License-Identifier: LGPL-2.1-or-later
4 * Very simple multibyte buffer editor. Allows to maintaine the current
5 * position in the string, add and remove chars on the current position.
7 * This file may be distributed under the terms of the
8 * GNU Lesser General Public License.
10 * Copyright (C) 2017 Karel Zak <kzak@redhat.com>
20 struct mbs_editor
*mbs_new_edit(char *buf
, size_t bufsz
, size_t ncells
)
22 struct mbs_editor
*edit
= calloc(1, sizeof(*edit
));
26 edit
->max_bytes
= bufsz
;
27 edit
->max_cells
= ncells
;
28 edit
->cur_cells
= mbs_safe_width(buf
);
29 edit
->cur_bytes
= strlen(buf
);
34 char *mbs_free_edit(struct mbs_editor
*edit
)
36 char *ret
= edit
? edit
->buf
: NULL
;
42 static size_t mbs_next(const char *str
, size_t *ncells
)
51 n
= mbrtowc(&wc
, str
, MB_CUR_MAX
, NULL
);
52 *ncells
= wcwidth(wc
);
62 static size_t mbs_prev(const char *start
, const char *end
, size_t *ncells
)
69 if (!start
|| !end
|| start
== end
|| !*start
)
74 n
= mbrtowc(&wc
, p
, MB_CUR_MAX
, NULL
);
77 if (n
== (size_t) -1 || n
== (size_t) -2)
85 *ncells
= wcwidth(wc
);
88 if (!start
|| !end
|| start
== end
|| !*start
)
95 int mbs_edit_goto(struct mbs_editor
*edit
, int where
)
99 if (edit
->cursor
== 0)
103 n
= mbs_prev(edit
->buf
, edit
->buf
+ edit
->cursor
, &cells
);
106 edit
->cursor_cells
-= cells
;
111 if (edit
->cursor_cells
>= edit
->cur_cells
)
115 n
= mbs_next(edit
->buf
+ edit
->cursor
, &cells
);
118 edit
->cursor_cells
+= cells
;
124 edit
->cursor_cells
= 0;
127 edit
->cursor
= edit
->cur_bytes
;
128 edit
->cursor_cells
= edit
->cur_cells
;
137 /* Remove next MB from @str, returns number of removed bytes */
138 static size_t remove_next(char *str
, size_t *ncells
)
141 size_t bytes
, move_bytes
, n
;
143 n
= mbs_next(str
, ncells
);
145 move_bytes
= bytes
- n
;
147 memmove(str
, str
+ n
, move_bytes
);
148 str
[bytes
- n
] = '\0';
152 static size_t mbs_insert(char *str
, wint_t c
, size_t *ncells
)
159 wchar_t wc
= (wchar_t) c
;
160 in
= malloc(MB_CUR_MAX
);
165 if (n
== (size_t) -1)
167 *ncells
= wcwidth(wc
);
174 memmove(str
+ n
, str
, bytes
);
176 str
[bytes
+ n
] = '\0';
184 static int mbs_edit_remove(struct mbs_editor
*edit
)
188 if (edit
->cur_cells
== 0 || edit
->cursor
>= edit
->cur_bytes
)
191 n
= remove_next(edit
->buf
+ edit
->cursor
, &ncells
);
195 edit
->cur_bytes
-= n
;
196 edit
->cur_cells
= mbs_safe_width(edit
->buf
);
200 int mbs_edit_delete(struct mbs_editor
*edit
)
202 if (edit
->cursor
>= edit
->cur_bytes
203 && mbs_edit_goto(edit
, MBS_EDIT_LEFT
) == 1)
206 return mbs_edit_remove(edit
);
209 int mbs_edit_backspace(struct mbs_editor
*edit
)
211 if (mbs_edit_goto(edit
, MBS_EDIT_LEFT
) == 0)
212 return mbs_edit_remove(edit
);
216 int mbs_edit_insert(struct mbs_editor
*edit
, wint_t c
)
220 if (edit
->cur_bytes
+ MB_CUR_MAX
> edit
->max_bytes
)
223 n
= mbs_insert(edit
->buf
+ edit
->cursor
, c
, &ncells
);
228 edit
->cursor_cells
+= ncells
;
229 edit
->cur_bytes
+= n
;
230 edit
->cur_cells
= mbs_safe_width(edit
->buf
);