]>
git.ipfire.org Git - thirdparty/util-linux.git/blob - lib/mbsedit.c
2 * Very simple multibyte buffer editor. Allows to maintaine the current
3 * position in the string, add and remove chars on the current position.
5 * This file may be distributed under the terms of the
6 * GNU Lesser General Public License.
8 * Copyright (C) 2017 Karel Zak <kzak@redhat.com>
18 struct mbs_editor
*mbs_new_edit(char *buf
, size_t bufsz
, size_t ncells
)
20 struct mbs_editor
*edit
= calloc(1, sizeof(*edit
));
24 edit
->max_bytes
= bufsz
;
25 edit
->max_cells
= ncells
;
26 edit
->cur_cells
= mbs_safe_width(buf
);
27 edit
->cur_bytes
= strlen(buf
);
32 char *mbs_free_edit(struct mbs_editor
*edit
)
34 char *ret
= edit
? edit
->buf
: NULL
;
40 static size_t mbs_next(const char *str
, size_t *ncells
)
49 n
= mbrtowc(&wc
, str
, MB_CUR_MAX
, NULL
);
50 *ncells
= wcwidth(wc
);
60 static size_t mbs_prev(const char *start
, const char *end
, size_t *ncells
)
67 if (!start
|| !end
|| start
== end
|| !*start
)
72 n
= mbrtowc(&wc
, p
, MB_CUR_MAX
, NULL
);
75 if (n
== (size_t) -1 || n
== (size_t) -2)
83 *ncells
= wcwidth(wc
);
86 if (!start
|| !end
|| start
== end
|| !*start
)
93 int mbs_edit_goto(struct mbs_editor
*edit
, int where
)
97 if (edit
->cursor
== 0)
101 n
= mbs_prev(edit
->buf
, edit
->buf
+ edit
->cursor
, &cells
);
104 edit
->cursor_cells
-= cells
;
109 if (edit
->cursor_cells
>= edit
->cur_cells
)
113 n
= mbs_next(edit
->buf
+ edit
->cursor
, &cells
);
116 edit
->cursor_cells
+= cells
;
122 edit
->cursor_cells
= 0;
125 edit
->cursor
= edit
->cur_bytes
;
126 edit
->cursor_cells
= edit
->cur_cells
;
135 /* Remove next MB from @str, returns number of removed bytes */
136 static size_t remove_next(char *str
, size_t *ncells
)
139 size_t bytes
, move_bytes
, n
;
141 n
= mbs_next(str
, ncells
);
143 move_bytes
= bytes
- n
;
145 memmove(str
, str
+ n
, move_bytes
);
146 str
[bytes
- n
] = '\0';
150 static size_t mbs_insert(char *str
, wint_t c
, size_t *ncells
)
157 wchar_t wc
= (wchar_t) c
;
158 char in_buf
[MB_CUR_MAX
];
160 n
= wctomb(in_buf
, wc
);
161 if (n
== (size_t) -1)
163 *ncells
= wcwidth(wc
);
171 memmove(str
+ n
, str
, bytes
);
173 str
[bytes
+ n
] = '\0';
177 static int mbs_edit_remove(struct mbs_editor
*edit
)
181 if (edit
->cur_cells
== 0 || edit
->cursor
>= edit
->cur_bytes
)
184 n
= remove_next(edit
->buf
+ edit
->cursor
, &ncells
);
188 edit
->cur_bytes
-= n
;
189 edit
->cur_cells
= mbs_safe_width(edit
->buf
);
193 int mbs_edit_delete(struct mbs_editor
*edit
)
195 if (edit
->cursor
>= edit
->cur_bytes
196 && mbs_edit_goto(edit
, MBS_EDIT_LEFT
) == 1)
199 return mbs_edit_remove(edit
);
202 int mbs_edit_backspace(struct mbs_editor
*edit
)
204 if (mbs_edit_goto(edit
, MBS_EDIT_LEFT
) == 0)
205 return mbs_edit_remove(edit
);
209 int mbs_edit_insert(struct mbs_editor
*edit
, wint_t c
)
213 if (edit
->cur_bytes
+ MB_CUR_MAX
> edit
->max_bytes
)
216 n
= mbs_insert(edit
->buf
+ edit
->cursor
, c
, &ncells
);
221 edit
->cursor_cells
+= ncells
;
222 edit
->cur_bytes
+= n
;
223 edit
->cur_cells
= mbs_safe_width(edit
->buf
);