2007-07-27 07:13:27 -04:00
|
|
|
/** Textarea form item handlers
|
|
|
|
* @file */
|
2005-09-15 09:58:31 -04:00
|
|
|
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
|
|
#include "config.h"
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifndef _GNU_SOURCE
|
|
|
|
#define _GNU_SOURCE /* XXX: we want memrchr() ! */
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
#ifdef HAVE_UNISTD_H
|
|
|
|
#include <unistd.h>
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#include "elinks.h"
|
|
|
|
|
|
|
|
#include "bfu/dialog.h"
|
|
|
|
#include "document/document.h"
|
|
|
|
#include "document/forms.h"
|
|
|
|
#include "document/view.h"
|
2021-08-08 15:25:08 -04:00
|
|
|
#include "intl/libintl.h"
|
2005-09-15 09:58:31 -04:00
|
|
|
#include "session/session.h"
|
|
|
|
#include "terminal/draw.h"
|
|
|
|
#include "terminal/window.h"
|
|
|
|
#include "util/error.h"
|
|
|
|
#include "util/file.h"
|
|
|
|
#include "util/memory.h"
|
|
|
|
#include "util/string.h"
|
|
|
|
#include "viewer/action.h"
|
|
|
|
#include "viewer/text/form.h"
|
|
|
|
#include "viewer/text/textarea.h"
|
|
|
|
#include "viewer/text/view.h"
|
|
|
|
|
|
|
|
|
|
|
|
struct line_info {
|
|
|
|
int start;
|
|
|
|
int end;
|
2006-09-17 09:12:47 -04:00
|
|
|
#ifdef CONFIG_UTF8
|
2006-05-06 16:36:48 -04:00
|
|
|
int last_char_width;
|
|
|
|
int split_prev:1;
|
|
|
|
int split_next:1;
|
2006-09-17 09:12:47 -04:00
|
|
|
#endif /* CONFIG_UTF8 */
|
2005-09-15 09:58:31 -04:00
|
|
|
};
|
|
|
|
|
2007-07-27 07:13:27 -04:00
|
|
|
/** We add two extra entries to the table so the ending info can be added
|
2005-09-15 09:58:31 -04:00
|
|
|
* without reallocating. */
|
|
|
|
#define realloc_line_info(info, size) \
|
2006-02-17 12:32:59 -05:00
|
|
|
mem_align_alloc(info, size, (size) + 3, 0xFF)
|
2005-09-15 09:58:31 -04:00
|
|
|
|
2006-09-17 09:12:47 -04:00
|
|
|
#ifdef CONFIG_UTF8
|
2007-07-27 07:13:27 -04:00
|
|
|
/** Allocates a line_info table describing the layout of the textarea buffer.
|
2006-02-01 18:03:03 -05:00
|
|
|
*
|
2007-07-27 11:58:09 -04:00
|
|
|
* @param text the text to format; must be in UTF-8
|
2007-07-27 07:13:27 -04:00
|
|
|
* @param width is max width and the offset at which @a text will be
|
|
|
|
* wrapped
|
|
|
|
* @param wrap controls how the wrapping of @a text is performed
|
|
|
|
* @param format is non zero the @a text will be modified to make it
|
|
|
|
* suitable for encoding it for form posting
|
2006-02-01 18:03:03 -05:00
|
|
|
*/
|
|
|
|
static struct line_info *
|
2021-01-02 10:20:27 -05:00
|
|
|
format_textutf8(char *text, int width, enum form_wrap wrap, int format)
|
2006-02-01 18:03:03 -05:00
|
|
|
{
|
|
|
|
struct line_info *line = NULL;
|
|
|
|
int line_number = 0;
|
|
|
|
int begin = 0;
|
|
|
|
int pos = 0;
|
2021-01-02 10:20:27 -05:00
|
|
|
char *text_end;
|
2006-02-01 18:03:03 -05:00
|
|
|
int skip;
|
2021-01-02 10:20:27 -05:00
|
|
|
char *wrappos=NULL;
|
2006-05-06 14:50:59 -04:00
|
|
|
int chars_cells=0; /* Number of console chars on line */
|
2006-02-01 18:03:03 -05:00
|
|
|
|
|
|
|
assert(text);
|
|
|
|
if_assert_failed return NULL;
|
|
|
|
|
|
|
|
/* Allocate the ending entries */
|
|
|
|
if (!realloc_line_info(&line, 0))
|
|
|
|
return NULL;
|
|
|
|
|
2006-12-02 09:48:48 -05:00
|
|
|
text_end = text + strlen(text);
|
2006-02-01 18:03:03 -05:00
|
|
|
while (text[pos]) {
|
2006-12-02 09:48:48 -05:00
|
|
|
int char_cells = utf8_char2cells(&text[pos], text_end);
|
2006-02-01 18:03:03 -05:00
|
|
|
|
|
|
|
if (text[pos] == ' ')
|
|
|
|
wrappos = &text[pos];
|
|
|
|
|
|
|
|
if (text[pos] == '\n') {
|
|
|
|
skip = 1;
|
|
|
|
|
2006-05-06 16:36:48 -04:00
|
|
|
} else if (wrap == FORM_WRAP_NONE || chars_cells + char_cells < width) {
|
2006-02-01 18:03:03 -05:00
|
|
|
pos += utf8charlen(&text[pos]);
|
2006-05-06 16:36:48 -04:00
|
|
|
chars_cells += char_cells;
|
2006-02-01 18:03:03 -05:00
|
|
|
continue;
|
2006-05-06 16:36:48 -04:00
|
|
|
|
2006-02-01 18:03:03 -05:00
|
|
|
} else {
|
|
|
|
if (wrappos) {
|
|
|
|
/* When formatting text for form submitting we
|
|
|
|
* have to apply the wrapping mode. */
|
|
|
|
if (wrap == FORM_WRAP_HARD && format)
|
|
|
|
*wrappos = '\n';
|
|
|
|
pos = wrappos - text;
|
|
|
|
}
|
|
|
|
skip = !!wrappos;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!realloc_line_info(&line, line_number)) {
|
|
|
|
mem_free_if(line);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2006-05-06 16:36:48 -04:00
|
|
|
line[line_number].last_char_width = char_cells;
|
|
|
|
line[line_number].split_next = !skip;
|
2006-02-01 18:03:03 -05:00
|
|
|
line[line_number].start = begin;
|
|
|
|
line[line_number++].end = pos;
|
2006-05-06 16:36:48 -04:00
|
|
|
line[line_number].split_prev = !skip;
|
|
|
|
|
2006-02-01 18:03:03 -05:00
|
|
|
begin = pos += skip;
|
2006-05-06 16:36:48 -04:00
|
|
|
|
|
|
|
chars_cells = 0;
|
2006-07-27 03:51:10 -04:00
|
|
|
wrappos = NULL;
|
2006-02-01 18:03:03 -05:00
|
|
|
}
|
|
|
|
|
2006-05-06 16:36:48 -04:00
|
|
|
line[line_number].split_next = 0;
|
|
|
|
|
2006-02-01 18:03:03 -05:00
|
|
|
/* Flush the last text before the loop ended */
|
|
|
|
line[line_number].start = begin;
|
|
|
|
line[line_number++].end = pos;
|
|
|
|
|
|
|
|
/* Add end marker */
|
|
|
|
line[line_number].start = line[line_number].end = -1;
|
|
|
|
|
2006-05-06 16:36:48 -04:00
|
|
|
line[line_number].split_next = line[line_number].split_prev = 0;
|
|
|
|
line[0].split_prev = 0;
|
|
|
|
|
2006-02-01 18:03:03 -05:00
|
|
|
return line;
|
|
|
|
}
|
2006-09-17 09:12:47 -04:00
|
|
|
#endif /* CONFIG_UTF8 */
|
2006-02-01 18:03:03 -05:00
|
|
|
|
2007-07-27 07:13:27 -04:00
|
|
|
/** Allocates a line_info table describing the layout of the textarea buffer.
|
2005-09-15 09:58:31 -04:00
|
|
|
*
|
2007-07-27 11:58:09 -04:00
|
|
|
* @param text the text to format; must be in a unibyte charset
|
2007-07-27 07:13:27 -04:00
|
|
|
* @param width is max width and the offset at which @a text will be
|
|
|
|
* wrapped
|
|
|
|
* @param wrap controls how the wrapping of @a text is performed
|
|
|
|
* @param format is non zero the @a text will be modified to make it
|
|
|
|
* suitable for encoding it for form posting
|
2005-09-15 09:58:31 -04:00
|
|
|
*/
|
|
|
|
static struct line_info *
|
2021-01-02 10:20:27 -05:00
|
|
|
format_text(char *text, int width, enum form_wrap wrap, int format)
|
2005-09-15 09:58:31 -04:00
|
|
|
{
|
|
|
|
struct line_info *line = NULL;
|
|
|
|
int line_number = 0;
|
|
|
|
int begin = 0;
|
|
|
|
int pos = 0;
|
|
|
|
int skip;
|
|
|
|
|
|
|
|
assert(text);
|
|
|
|
if_assert_failed return NULL;
|
|
|
|
|
|
|
|
/* Allocate the ending entries */
|
|
|
|
if (!realloc_line_info(&line, 0))
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
while (text[pos]) {
|
|
|
|
if (text[pos] == '\n') {
|
|
|
|
skip = 1;
|
|
|
|
|
|
|
|
} else if (wrap == FORM_WRAP_NONE || pos - begin < width) {
|
|
|
|
pos++;
|
|
|
|
continue;
|
|
|
|
|
|
|
|
} else {
|
2021-01-02 10:20:27 -05:00
|
|
|
char *wrappos;
|
2005-09-15 09:58:31 -04:00
|
|
|
|
|
|
|
/* Find a place to wrap the text */
|
2022-01-26 12:18:44 -05:00
|
|
|
wrappos = (char *)memrchr(&text[begin], ' ', pos - begin);
|
2005-09-15 09:58:31 -04:00
|
|
|
if (wrappos) {
|
|
|
|
/* When formatting text for form submitting we
|
|
|
|
* have to apply the wrapping mode. */
|
|
|
|
if (wrap == FORM_WRAP_HARD && format)
|
|
|
|
*wrappos = '\n';
|
|
|
|
pos = wrappos - text;
|
|
|
|
}
|
|
|
|
skip = !!wrappos;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!realloc_line_info(&line, line_number)) {
|
|
|
|
mem_free_if(line);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
line[line_number].start = begin;
|
|
|
|
line[line_number++].end = pos;
|
|
|
|
begin = pos += skip;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Flush the last text before the loop ended */
|
|
|
|
line[line_number].start = begin;
|
|
|
|
line[line_number++].end = pos;
|
|
|
|
|
|
|
|
/* Add end marker */
|
|
|
|
line[line_number].start = line[line_number].end = -1;
|
|
|
|
|
|
|
|
return line;
|
|
|
|
}
|
|
|
|
|
2007-07-27 07:13:27 -04:00
|
|
|
/** Searches for @a cursor_position (aka. position in the
|
|
|
|
* form_state.value string) for the corresponding entry in the @a line
|
|
|
|
* info. Returns the index or -1 if position is not found. */
|
2005-09-15 09:58:31 -04:00
|
|
|
static int
|
|
|
|
get_textarea_line_number(struct line_info *line, int cursor_position)
|
|
|
|
{
|
|
|
|
int idx;
|
|
|
|
|
|
|
|
for (idx = 0; line[idx].start != -1; idx++) {
|
|
|
|
int wrap;
|
|
|
|
|
|
|
|
if (cursor_position < line[idx].start) continue;
|
|
|
|
|
|
|
|
wrap = (line[idx + 1].start == line[idx].end);
|
|
|
|
if (cursor_position >= line[idx].end + !wrap) continue;
|
|
|
|
|
|
|
|
return idx;
|
|
|
|
}
|
|
|
|
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2007-07-27 07:13:27 -04:00
|
|
|
/** Fixes up the form_state.vpos and form_state.vypos members.
|
|
|
|
* @returns the logical position in the textarea view. */
|
2006-09-17 09:12:47 -04:00
|
|
|
#ifdef CONFIG_UTF8
|
2006-05-06 16:36:48 -04:00
|
|
|
int
|
2018-09-09 13:18:53 -04:00
|
|
|
area_cursor(struct el_form_control *fc, struct form_state *fs, int utf8)
|
2005-09-15 09:58:31 -04:00
|
|
|
{
|
|
|
|
struct line_info *line;
|
|
|
|
int x, y;
|
|
|
|
|
|
|
|
assert(fc && fs);
|
|
|
|
if_assert_failed return 0;
|
|
|
|
|
2006-02-01 18:03:03 -05:00
|
|
|
if (utf8)
|
|
|
|
line = format_textutf8(fs->value, fc->cols, fc->wrap, 0);
|
|
|
|
else
|
|
|
|
line = format_text(fs->value, fc->cols, fc->wrap, 0);
|
2006-05-06 16:36:48 -04:00
|
|
|
|
2005-09-15 09:58:31 -04:00
|
|
|
if (!line) return 0;
|
|
|
|
|
2006-05-06 16:36:48 -04:00
|
|
|
if (fs->state_cell)
|
|
|
|
y = get_textarea_line_number(line, fs->state_cell);
|
|
|
|
else
|
|
|
|
y = get_textarea_line_number(line, fs->state);
|
|
|
|
|
2005-09-15 09:58:31 -04:00
|
|
|
if (y == -1) {
|
|
|
|
mem_free(line);
|
|
|
|
return 0;
|
|
|
|
}
|
2006-05-06 16:36:48 -04:00
|
|
|
|
2006-01-14 16:44:00 -05:00
|
|
|
if (utf8) {
|
2006-05-06 16:36:48 -04:00
|
|
|
if (fs->state_cell) {
|
|
|
|
x = utf8_ptr2cells(fs->value + line[y].start,
|
|
|
|
fs->value + fs->state_cell);
|
|
|
|
x += line[y].last_char_width;
|
|
|
|
} else
|
|
|
|
x = utf8_ptr2cells(fs->value + line[y].start,
|
|
|
|
fs->value + fs->state);
|
|
|
|
} else {
|
|
|
|
x = fs->state - line[y].start;
|
|
|
|
if (fc->wrap && x == fc->cols) x--;
|
|
|
|
}
|
2006-01-14 16:44:00 -05:00
|
|
|
|
2006-05-06 16:36:48 -04:00
|
|
|
mem_free(line);
|
2006-02-03 20:18:00 -05:00
|
|
|
|
2006-05-06 16:36:48 -04:00
|
|
|
int_bounds(&fs->vpos, x - fc->cols + 1, x);
|
|
|
|
int_bounds(&fs->vypos, y - fc->rows + 1, y);
|
|
|
|
|
|
|
|
x -= fs->vpos;
|
|
|
|
y -= fs->vypos;
|
|
|
|
|
|
|
|
return y * fc->cols + x;
|
|
|
|
}
|
|
|
|
|
|
|
|
#else
|
|
|
|
|
|
|
|
int
|
2018-09-09 13:18:53 -04:00
|
|
|
area_cursor(struct el_form_control *fc, struct form_state *fs)
|
2006-05-06 16:36:48 -04:00
|
|
|
{
|
|
|
|
struct line_info *line;
|
|
|
|
int x, y;
|
|
|
|
|
|
|
|
assert(fc && fs);
|
|
|
|
if_assert_failed return 0;
|
|
|
|
|
|
|
|
line = format_text(fs->value, fc->cols, fc->wrap, 0);
|
|
|
|
if (!line) return 0;
|
|
|
|
|
|
|
|
y = get_textarea_line_number(line, fs->state);
|
|
|
|
if (y == -1) {
|
|
|
|
mem_free(line);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
x = fs->state - line[y].start;
|
2005-09-15 09:58:31 -04:00
|
|
|
|
|
|
|
mem_free(line);
|
|
|
|
|
|
|
|
if (fc->wrap && x == fc->cols) x--;
|
|
|
|
|
|
|
|
int_bounds(&fs->vpos, x - fc->cols + 1, x);
|
|
|
|
int_bounds(&fs->vypos, y - fc->rows + 1, y);
|
|
|
|
|
|
|
|
x -= fs->vpos;
|
|
|
|
y -= fs->vypos;
|
|
|
|
|
|
|
|
return y * fc->cols + x;
|
|
|
|
}
|
2006-05-06 16:36:48 -04:00
|
|
|
#endif
|
2005-09-15 09:58:31 -04:00
|
|
|
|
2006-09-17 09:12:47 -04:00
|
|
|
#ifdef CONFIG_UTF8
|
2006-01-14 16:44:00 -05:00
|
|
|
static void
|
|
|
|
draw_textarea_utf8(struct terminal *term, struct form_state *fs,
|
|
|
|
struct document_view *doc_view, struct link *link)
|
|
|
|
{
|
|
|
|
struct line_info *line, *linex;
|
2018-09-09 13:18:53 -04:00
|
|
|
struct el_form_control *fc;
|
2018-09-09 13:14:56 -04:00
|
|
|
struct el_box *box;
|
2006-01-14 16:44:00 -05:00
|
|
|
int vx, vy;
|
|
|
|
int sl, ye;
|
2006-05-06 15:10:16 -04:00
|
|
|
int x, xbase, y;
|
2006-01-14 16:44:00 -05:00
|
|
|
|
|
|
|
assert(term && doc_view && doc_view->document && doc_view->vs && link);
|
|
|
|
if_assert_failed return;
|
|
|
|
fc = get_link_form_control(link);
|
2007-03-11 06:22:02 -04:00
|
|
|
assertm(fc != NULL, "link %d has no form control", (int) (link - doc_view->document->links));
|
2006-01-14 16:44:00 -05:00
|
|
|
if_assert_failed return;
|
|
|
|
|
|
|
|
box = &doc_view->box;
|
|
|
|
vx = doc_view->vs->x;
|
|
|
|
vy = doc_view->vs->y;
|
|
|
|
|
|
|
|
if (!link->npoints) return;
|
|
|
|
area_cursor(fc, fs, 1);
|
2006-02-01 18:03:03 -05:00
|
|
|
linex = format_textutf8(fs->value, fc->cols, fc->wrap, 0);
|
2006-01-14 16:44:00 -05:00
|
|
|
if (!linex) return;
|
|
|
|
line = linex;
|
|
|
|
sl = fs->vypos;
|
|
|
|
while (line->start != -1 && sl) sl--, line++;
|
|
|
|
|
2006-05-06 15:10:16 -04:00
|
|
|
xbase = link->points[0].x + box->x - vx;
|
2006-01-14 16:44:00 -05:00
|
|
|
y = link->points[0].y + box->y - vy;
|
|
|
|
ye = y + fc->rows;
|
|
|
|
|
|
|
|
for (; line->start != -1 && y < ye; line++, y++) {
|
|
|
|
int i;
|
2021-01-02 10:20:27 -05:00
|
|
|
char *text, *end;
|
2006-01-14 16:44:00 -05:00
|
|
|
|
|
|
|
text = fs->value + line->start;
|
|
|
|
end = fs->value + line->end;
|
|
|
|
|
2006-05-06 16:36:48 -04:00
|
|
|
text += utf8_cells2bytes(text, fs->vpos, end);
|
2006-01-14 16:44:00 -05:00
|
|
|
|
|
|
|
if (!row_is_in_box(box, y)) continue;
|
|
|
|
|
2006-05-06 15:10:16 -04:00
|
|
|
for (i = 0, x = xbase; i < fc->cols; i++, x++) {
|
|
|
|
unicode_val_T data;
|
2006-01-14 16:44:00 -05:00
|
|
|
|
2006-05-06 16:36:48 -04:00
|
|
|
if (i >= -fs->vpos && text < end) {
|
2006-12-02 11:35:51 -05:00
|
|
|
/* utf8_to_unicode will increment text. */
|
2006-09-17 09:06:22 -04:00
|
|
|
data = utf8_to_unicode(&text, end);
|
2006-12-02 11:35:51 -05:00
|
|
|
} else
|
|
|
|
data = '_';
|
|
|
|
|
|
|
|
if (col_is_in_box(box, x)) {
|
|
|
|
int cell = unicode_to_cell(data);
|
|
|
|
|
2006-05-06 16:36:48 -04:00
|
|
|
if (cell == 2) {
|
|
|
|
draw_char_data(term, x++, y, data);
|
|
|
|
i++;
|
|
|
|
data = UCS_NO_CHAR;
|
|
|
|
}
|
|
|
|
|
2006-12-02 11:35:51 -05:00
|
|
|
draw_char_data(term, x, y, data);
|
|
|
|
}
|
2006-01-14 16:44:00 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for (; y < ye; y++) {
|
|
|
|
int i;
|
|
|
|
|
|
|
|
if (!row_is_in_box(box, y)) continue;
|
|
|
|
|
2006-05-06 15:10:16 -04:00
|
|
|
for (i = 0, x = xbase; i < fc->cols; i++, x++) {
|
|
|
|
if (col_is_in_box(box, x))
|
|
|
|
draw_char_data(term, x, y, '_');
|
2006-01-14 16:44:00 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
mem_free(linex);
|
|
|
|
}
|
2006-09-17 09:12:47 -04:00
|
|
|
#endif /* CONFIG_UTF8 */
|
2006-01-14 16:44:00 -05:00
|
|
|
|
2005-09-15 09:58:31 -04:00
|
|
|
void
|
|
|
|
draw_textarea(struct terminal *term, struct form_state *fs,
|
|
|
|
struct document_view *doc_view, struct link *link)
|
|
|
|
{
|
|
|
|
struct line_info *line, *linex;
|
2018-09-09 13:18:53 -04:00
|
|
|
struct el_form_control *fc;
|
2018-09-09 13:14:56 -04:00
|
|
|
struct el_box *box;
|
2005-09-15 09:58:31 -04:00
|
|
|
int vx, vy;
|
|
|
|
int sl, ye;
|
|
|
|
int x, y;
|
|
|
|
|
|
|
|
assert(term && doc_view && doc_view->document && doc_view->vs && link);
|
|
|
|
if_assert_failed return;
|
2006-01-14 16:44:00 -05:00
|
|
|
|
2006-09-17 09:12:47 -04:00
|
|
|
#ifdef CONFIG_UTF8
|
2007-05-20 08:31:02 -04:00
|
|
|
if (term->utf8_cp) {
|
2006-01-14 16:44:00 -05:00
|
|
|
draw_textarea_utf8(term, fs, doc_view, link);
|
|
|
|
return;
|
|
|
|
}
|
2006-09-17 09:12:47 -04:00
|
|
|
#endif /* CONFIG_UTF8 */
|
2005-09-15 09:58:31 -04:00
|
|
|
fc = get_link_form_control(link);
|
2007-03-11 06:22:02 -04:00
|
|
|
assertm(fc != NULL, "link %d has no form control", (int) (link - doc_view->document->links));
|
2005-09-15 09:58:31 -04:00
|
|
|
if_assert_failed return;
|
|
|
|
|
|
|
|
box = &doc_view->box;
|
|
|
|
vx = doc_view->vs->x;
|
|
|
|
vy = doc_view->vs->y;
|
|
|
|
|
|
|
|
if (!link->npoints) return;
|
2006-09-17 09:12:47 -04:00
|
|
|
#ifdef CONFIG_UTF8
|
2006-01-14 16:44:00 -05:00
|
|
|
area_cursor(fc, fs, 0);
|
2006-02-02 18:27:01 -05:00
|
|
|
#else
|
|
|
|
area_cursor(fc, fs);
|
2006-09-17 09:12:47 -04:00
|
|
|
#endif /* CONFIG_UTF8 */
|
2005-09-15 09:58:31 -04:00
|
|
|
linex = format_text(fs->value, fc->cols, fc->wrap, 0);
|
|
|
|
if (!linex) return;
|
|
|
|
line = linex;
|
|
|
|
sl = fs->vypos;
|
|
|
|
while (line->start != -1 && sl) sl--, line++;
|
|
|
|
|
|
|
|
x = link->points[0].x + box->x - vx;
|
|
|
|
y = link->points[0].y + box->y - vy;
|
|
|
|
ye = y + fc->rows;
|
|
|
|
|
|
|
|
for (; line->start != -1 && y < ye; line++, y++) {
|
|
|
|
int i;
|
|
|
|
|
|
|
|
if (!row_is_in_box(box, y)) continue;
|
|
|
|
|
|
|
|
for (i = 0; i < fc->cols; i++) {
|
|
|
|
unsigned char data;
|
|
|
|
int xi = x + i;
|
|
|
|
|
|
|
|
if (!col_is_in_box(box, xi))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (i >= -fs->vpos
|
|
|
|
&& i + fs->vpos < line->end - line->start)
|
|
|
|
data = fs->value[line->start + i + fs->vpos];
|
|
|
|
else
|
|
|
|
data = '_';
|
|
|
|
|
|
|
|
draw_char_data(term, xi, y, data);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for (; y < ye; y++) {
|
|
|
|
int i;
|
|
|
|
|
|
|
|
if (!row_is_in_box(box, y)) continue;
|
|
|
|
|
|
|
|
for (i = 0; i < fc->cols; i++) {
|
|
|
|
int xi = x + i;
|
|
|
|
|
|
|
|
if (col_is_in_box(box, xi))
|
|
|
|
draw_char_data(term, xi, y, '_');
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
mem_free(linex);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2021-01-02 10:20:27 -05:00
|
|
|
char *
|
2005-09-15 09:58:31 -04:00
|
|
|
encode_textarea(struct submitted_value *sv)
|
|
|
|
{
|
2018-09-09 13:18:53 -04:00
|
|
|
struct el_form_control *fc;
|
2005-09-15 09:58:31 -04:00
|
|
|
void *blabla;
|
|
|
|
|
|
|
|
assert(sv && sv->value);
|
|
|
|
if_assert_failed return NULL;
|
|
|
|
|
|
|
|
fc = sv->form_control;
|
|
|
|
|
|
|
|
/* We need to reformat text now if it has to be wrapped hard, just
|
|
|
|
* before encoding it. */
|
2006-02-01 18:03:03 -05:00
|
|
|
/* TODO: Do we need here UTF-8 format or not? --scrool */
|
2005-09-15 09:58:31 -04:00
|
|
|
blabla = format_text(sv->value, fc->cols, fc->wrap, 1);
|
|
|
|
mem_free_if(blabla);
|
|
|
|
|
2008-11-03 16:56:49 -05:00
|
|
|
return encode_crlf(sv);
|
2005-09-15 09:58:31 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2007-07-27 07:13:27 -04:00
|
|
|
/** We use some evil hacking in order to make external textarea editor working.
|
2005-09-15 09:58:31 -04:00
|
|
|
* We need to have some way how to be notified that the editor finished and we
|
|
|
|
* should reload content of the textarea. So we use global variable
|
2007-07-27 07:13:27 -04:00
|
|
|
* @c textarea_editor as a flag whether we have one running, and if we have, we
|
2005-09-15 09:58:31 -04:00
|
|
|
* just call textarea_edit(1, ...). Then we recover our state from static
|
|
|
|
* variables, reload content of textarea back from file and clean up.
|
|
|
|
*
|
|
|
|
* Unfortunately, we can't support calling of editor from non-master links
|
|
|
|
* session, as it would be extremely ugly to hack (you would have to transfer
|
|
|
|
* the content of it back to master somehow, add special flags for not deleting
|
|
|
|
* of 'delete' etc) and I'm not going to do that now. Inter-links communication
|
|
|
|
* *NEEDS* rewrite, as it looks just like quick messy hack now. --pasky */
|
|
|
|
|
2021-01-02 10:20:27 -05:00
|
|
|
static char *
|
|
|
|
save_textarea_file(char *value)
|
2005-09-15 09:58:31 -04:00
|
|
|
{
|
2021-01-02 10:20:27 -05:00
|
|
|
char *filename;
|
2007-03-05 15:41:17 -05:00
|
|
|
FILE *fp = NULL;
|
|
|
|
int fd;
|
2007-03-05 15:48:42 -05:00
|
|
|
size_t nmemb, len;
|
2005-09-15 09:58:31 -04:00
|
|
|
|
|
|
|
filename = get_tempdir_filename("elinks-area-XXXXXX");
|
|
|
|
if (!filename) return NULL;
|
|
|
|
|
2007-03-05 15:41:17 -05:00
|
|
|
fd = safe_mkstemp(filename);
|
2007-03-05 15:44:58 -05:00
|
|
|
if (fd < 0) {
|
|
|
|
mem_free(filename);
|
|
|
|
return NULL;
|
|
|
|
}
|
2005-09-15 09:58:31 -04:00
|
|
|
|
2007-03-05 15:48:42 -05:00
|
|
|
len = strlen(value);
|
|
|
|
if (len == 0) return filename;
|
|
|
|
|
2007-03-05 15:44:58 -05:00
|
|
|
fp = fdopen(fd, "w");
|
|
|
|
if (!fp) {
|
2007-03-05 15:47:09 -05:00
|
|
|
|
|
|
|
error:
|
2007-03-05 15:44:58 -05:00
|
|
|
unlink(filename);
|
2005-09-15 09:58:31 -04:00
|
|
|
mem_free(filename);
|
2007-03-05 15:44:58 -05:00
|
|
|
close(fd);
|
|
|
|
return NULL;
|
2005-09-15 09:58:31 -04:00
|
|
|
}
|
|
|
|
|
2007-03-05 15:48:42 -05:00
|
|
|
nmemb = fwrite(value, len, 1, fp);
|
2007-03-05 15:47:09 -05:00
|
|
|
if (nmemb != 1) {
|
|
|
|
fclose(fp);
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (fclose(fp) != 0)
|
|
|
|
goto error;
|
2007-03-05 15:44:58 -05:00
|
|
|
|
2005-09-15 09:58:31 -04:00
|
|
|
return filename;
|
|
|
|
}
|
|
|
|
|
2007-09-01 08:02:21 -04:00
|
|
|
struct textarea_data {
|
|
|
|
LIST_HEAD(struct textarea_data);
|
|
|
|
size_t fc_maxlength;
|
|
|
|
struct form_state *fs;
|
|
|
|
struct terminal *term;
|
|
|
|
struct document_view *doc_view;
|
|
|
|
struct link *link;
|
2021-01-02 10:20:27 -05:00
|
|
|
char *fn;
|
2007-09-01 08:02:21 -04:00
|
|
|
};
|
|
|
|
|
2007-09-01 05:20:40 -04:00
|
|
|
static struct textarea_data *
|
|
|
|
init_textarea_data(struct terminal *term, struct form_state *fs,
|
|
|
|
struct document_view *doc_view, struct link *link)
|
|
|
|
{
|
|
|
|
struct textarea_data *td;
|
|
|
|
|
|
|
|
assert(fs && doc_view && link && term);
|
|
|
|
|
2022-01-16 15:08:50 -05:00
|
|
|
td = (struct textarea_data *)mem_calloc(1, sizeof(*td));
|
2007-09-01 05:20:40 -04:00
|
|
|
if (!td) return NULL;
|
|
|
|
|
|
|
|
td->fn = save_textarea_file(fs->value);
|
|
|
|
if (!td->fn) {
|
|
|
|
mem_free(td);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
td->fs = fs;
|
|
|
|
td->doc_view = doc_view;
|
|
|
|
td->link = link;
|
|
|
|
td->fc_maxlength = get_link_form_control(link)->maxlength;
|
|
|
|
td->term = term;
|
|
|
|
|
|
|
|
return td;
|
|
|
|
}
|
|
|
|
|
2007-09-01 07:58:09 -04:00
|
|
|
static void
|
2007-09-01 05:24:22 -04:00
|
|
|
done_textarea_data(struct textarea_data *td)
|
|
|
|
{
|
2007-09-01 19:46:37 -04:00
|
|
|
assert(td);
|
|
|
|
|
2007-09-01 05:24:22 -04:00
|
|
|
mem_free(td->fn);
|
|
|
|
mem_free(td);
|
|
|
|
}
|
|
|
|
|
2007-09-01 07:58:09 -04:00
|
|
|
void
|
|
|
|
free_textarea_data(struct terminal *term)
|
|
|
|
{
|
|
|
|
assert(term);
|
|
|
|
|
|
|
|
if (term->textarea_data)
|
2022-01-26 12:18:44 -05:00
|
|
|
done_textarea_data((struct textarea_data *)term->textarea_data);
|
2007-09-01 08:49:02 -04:00
|
|
|
|
|
|
|
term->textarea_data = NULL;
|
2007-09-01 07:58:09 -04:00
|
|
|
}
|
|
|
|
|
2005-09-15 09:58:31 -04:00
|
|
|
void
|
|
|
|
textarea_edit(int op, struct terminal *term_, struct form_state *fs_,
|
|
|
|
struct document_view *doc_view_, struct link *link_)
|
|
|
|
{
|
2007-09-01 19:46:37 -04:00
|
|
|
struct textarea_data *td = NULL;
|
2007-08-31 23:08:47 -04:00
|
|
|
|
|
|
|
assert ((op == 0 || op == 1) && term_);
|
2005-09-15 09:58:31 -04:00
|
|
|
if_assert_failed return;
|
|
|
|
|
|
|
|
if (op == 0 && get_cmd_opt_bool("anonymous")) {
|
|
|
|
info_box(term_, 0, N_("Error"), ALIGN_CENTER,
|
|
|
|
N_("You cannot launch an external"
|
|
|
|
" editor in the anonymous mode."));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2007-08-31 23:08:47 -04:00
|
|
|
if (op == 0) {
|
2021-01-02 10:20:27 -05:00
|
|
|
char *ed;
|
|
|
|
char *ex;
|
2005-09-15 09:58:31 -04:00
|
|
|
|
2007-08-30 17:09:14 -04:00
|
|
|
assert(fs_ && doc_view_ && link_ && term_);
|
|
|
|
|
2007-09-01 05:20:40 -04:00
|
|
|
td = init_textarea_data(term_, fs_, doc_view_, link_);
|
|
|
|
if (!td)
|
2007-08-31 23:08:47 -04:00
|
|
|
return;
|
2005-09-15 09:58:31 -04:00
|
|
|
|
2007-08-30 17:48:03 -04:00
|
|
|
ed = get_opt_str("document.browse.forms.editor",
|
2007-08-30 17:48:58 -04:00
|
|
|
doc_view_->session);
|
2005-09-15 09:58:31 -04:00
|
|
|
if (!ed || !*ed) {
|
|
|
|
ed = getenv("EDITOR");
|
|
|
|
if (!ed || !*ed) ed = "vi";
|
|
|
|
}
|
|
|
|
|
2021-01-02 10:20:27 -05:00
|
|
|
ex = straconcat(ed, " ", td->fn, (char *) NULL);
|
2005-09-15 09:58:31 -04:00
|
|
|
if (!ex) {
|
2007-08-31 23:08:47 -04:00
|
|
|
unlink(td->fn);
|
2007-09-01 05:24:22 -04:00
|
|
|
done_textarea_data(td);
|
|
|
|
return;
|
2005-09-15 09:58:31 -04:00
|
|
|
}
|
|
|
|
|
2007-09-01 05:02:01 -04:00
|
|
|
td->term->textarea_data = td;
|
2005-09-15 09:58:31 -04:00
|
|
|
|
2007-08-31 23:08:47 -04:00
|
|
|
exec_on_terminal(td->term, ex, "", TERM_EXEC_FG);
|
2005-09-15 09:58:31 -04:00
|
|
|
mem_free(ex);
|
|
|
|
|
2007-08-31 23:08:47 -04:00
|
|
|
return;
|
2005-09-15 09:58:31 -04:00
|
|
|
|
2007-08-31 23:08:47 -04:00
|
|
|
} else if (op == 1) {
|
2019-04-21 06:27:40 -04:00
|
|
|
struct string file;
|
2005-12-18 11:00:48 -05:00
|
|
|
|
2022-01-26 12:18:44 -05:00
|
|
|
td = (struct textarea_data *)term_->textarea_data;
|
2007-09-01 05:42:54 -04:00
|
|
|
term_->textarea_data = NULL;
|
2007-09-01 05:10:54 -04:00
|
|
|
assert(td);
|
2007-08-31 23:08:47 -04:00
|
|
|
|
|
|
|
if (!td->fs || !init_string(&file)
|
2007-09-01 05:24:22 -04:00
|
|
|
|| !add_file_to_string(&file, td->fn)) {
|
|
|
|
done_textarea_data(td);
|
|
|
|
return;
|
|
|
|
}
|
2005-09-15 09:58:31 -04:00
|
|
|
|
2007-08-31 23:08:47 -04:00
|
|
|
if (file.length > td->fc_maxlength) {
|
|
|
|
file.source[td->fc_maxlength] = '\0';
|
2007-03-10 17:25:42 -05:00
|
|
|
/* Casting size_t fc_maxlength to unsigned int
|
|
|
|
* and formatting it with "%u" is safe,
|
|
|
|
* because fc_maxlength is smaller than
|
|
|
|
* file.length, which is an int. */
|
2007-08-31 23:08:47 -04:00
|
|
|
info_box(td->term, MSGBOX_FREE_TEXT, N_("Warning"),
|
2005-12-18 11:23:52 -05:00
|
|
|
ALIGN_CENTER,
|
2007-08-31 23:08:47 -04:00
|
|
|
msg_text(td->term,
|
2005-12-18 11:23:52 -05:00
|
|
|
N_("You have exceeded the textarea's"
|
|
|
|
" size limit: your input is %d"
|
|
|
|
" bytes, but the maximum is %u"
|
|
|
|
" bytes.\n\n"
|
|
|
|
"Your input has been truncated,"
|
|
|
|
" but you can still recover the"
|
|
|
|
" text that you entered from"
|
|
|
|
" this file: %s"), file.length,
|
2007-08-31 23:08:47 -04:00
|
|
|
(unsigned int) td->fc_maxlength, td->fn));
|
2005-12-18 11:23:52 -05:00
|
|
|
} else {
|
2007-08-31 23:08:47 -04:00
|
|
|
unlink(td->fn);
|
2005-09-15 09:58:31 -04:00
|
|
|
}
|
|
|
|
|
2007-08-31 23:08:47 -04:00
|
|
|
mem_free(td->fs->value);
|
|
|
|
td->fs->value = file.source;
|
|
|
|
td->fs->state = file.length;
|
2005-12-18 11:00:48 -05:00
|
|
|
|
2007-08-31 23:08:47 -04:00
|
|
|
if (td->doc_view && td->link)
|
|
|
|
draw_form_entry(td->term, td->doc_view, td->link);
|
2005-09-15 09:58:31 -04:00
|
|
|
}
|
2007-09-01 05:24:22 -04:00
|
|
|
|
|
|
|
done_textarea_data(td);
|
2005-09-15 09:58:31 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
/* menu_func_T */
|
|
|
|
void
|
|
|
|
menu_textarea_edit(struct terminal *term, void *xxx, void *ses_)
|
|
|
|
{
|
2022-01-26 12:18:44 -05:00
|
|
|
struct session *ses = (struct session *)ses_;
|
2005-09-15 09:58:31 -04:00
|
|
|
struct document_view *doc_view;
|
|
|
|
struct link *link;
|
|
|
|
struct form_state *fs;
|
2018-09-09 13:18:53 -04:00
|
|
|
struct el_form_control *fc;
|
2005-09-15 09:58:31 -04:00
|
|
|
|
|
|
|
assert(term && ses);
|
|
|
|
if_assert_failed return;
|
|
|
|
|
|
|
|
doc_view = current_frame(ses);
|
|
|
|
|
|
|
|
assert(doc_view && doc_view->vs && doc_view->document);
|
|
|
|
if_assert_failed return;
|
|
|
|
|
|
|
|
link = get_current_link(doc_view);
|
|
|
|
if (!link) return;
|
|
|
|
|
|
|
|
fc = get_link_form_control(link);
|
|
|
|
if (form_field_is_readonly(fc))
|
|
|
|
return;
|
|
|
|
|
|
|
|
fs = find_form_state(doc_view, fc);
|
|
|
|
if (!fs) return;
|
|
|
|
|
|
|
|
textarea_edit(0, term, fs, doc_view, link);
|
|
|
|
}
|
|
|
|
|
2006-09-17 09:12:47 -04:00
|
|
|
#ifdef CONFIG_UTF8
|
2006-05-06 16:36:48 -04:00
|
|
|
static enum frame_event_status
|
2018-09-09 13:18:53 -04:00
|
|
|
textarea_op(struct form_state *fs, struct el_form_control *fc, int utf8,
|
2006-01-14 16:44:00 -05:00
|
|
|
int (*do_op)(struct form_state *, struct line_info *, int, int))
|
2005-09-15 09:58:31 -04:00
|
|
|
{
|
|
|
|
struct line_info *line;
|
|
|
|
int current, state;
|
2006-05-06 16:36:48 -04:00
|
|
|
int state_cell;
|
2005-09-15 09:58:31 -04:00
|
|
|
|
|
|
|
assert(fs && fs->value && fc);
|
|
|
|
if_assert_failed return FRAME_EVENT_OK;
|
|
|
|
|
2006-02-01 18:03:03 -05:00
|
|
|
if (utf8)
|
|
|
|
line = format_textutf8(fs->value, fc->cols, fc->wrap, 0);
|
|
|
|
else
|
|
|
|
line = format_text(fs->value, fc->cols, fc->wrap, 0);
|
2005-09-15 09:58:31 -04:00
|
|
|
if (!line) return FRAME_EVENT_OK;
|
|
|
|
|
|
|
|
current = get_textarea_line_number(line, fs->state);
|
|
|
|
state = fs->state;
|
2006-05-06 16:36:48 -04:00
|
|
|
state_cell = fs->state_cell;
|
|
|
|
if (do_op(fs, line, current, utf8)) {
|
2005-09-15 09:58:31 -04:00
|
|
|
mem_free(line);
|
|
|
|
return FRAME_EVENT_IGNORED;
|
|
|
|
}
|
|
|
|
|
|
|
|
mem_free(line);
|
2006-05-06 16:36:48 -04:00
|
|
|
return (fs->state == state && fs->state_cell == state_cell)
|
|
|
|
? FRAME_EVENT_OK : FRAME_EVENT_REFRESH;
|
2005-09-15 09:58:31 -04:00
|
|
|
}
|
|
|
|
|
2006-05-06 16:36:48 -04:00
|
|
|
#else
|
|
|
|
|
|
|
|
static enum frame_event_status
|
2018-09-09 13:18:53 -04:00
|
|
|
textarea_op(struct form_state *fs, struct el_form_control *fc,
|
2006-05-06 16:36:48 -04:00
|
|
|
int (*do_op)(struct form_state *, struct line_info *, int))
|
2006-01-14 16:44:00 -05:00
|
|
|
{
|
2006-05-06 16:36:48 -04:00
|
|
|
struct line_info *line;
|
|
|
|
int current, state;
|
|
|
|
|
|
|
|
assert(fs && fs->value && fc);
|
|
|
|
if_assert_failed return FRAME_EVENT_OK;
|
|
|
|
|
|
|
|
line = format_text(fs->value, fc->cols, fc->wrap, 0);
|
|
|
|
if (!line) return FRAME_EVENT_OK;
|
|
|
|
|
|
|
|
current = get_textarea_line_number(line, fs->state);
|
|
|
|
state = fs->state;
|
|
|
|
if (do_op(fs, line, current)) {
|
|
|
|
mem_free(line);
|
|
|
|
return FRAME_EVENT_IGNORED;
|
|
|
|
}
|
2006-01-14 16:44:00 -05:00
|
|
|
|
2006-05-06 16:36:48 -04:00
|
|
|
mem_free(line);
|
|
|
|
|
|
|
|
return fs->state == state ? FRAME_EVENT_OK : FRAME_EVENT_REFRESH;
|
2006-01-14 16:44:00 -05:00
|
|
|
}
|
2006-09-17 09:12:47 -04:00
|
|
|
#endif /* CONFIG_UTF8 */
|
2006-01-14 16:44:00 -05:00
|
|
|
|
2006-09-17 09:12:47 -04:00
|
|
|
#ifdef CONFIG_UTF8
|
2006-05-06 16:36:48 -04:00
|
|
|
void
|
|
|
|
new_pos(struct form_state *fs, struct line_info *line, int current, int max_cells)
|
2006-01-14 16:44:00 -05:00
|
|
|
{
|
2021-01-02 10:20:27 -05:00
|
|
|
char *text = fs->value + line[current].start;
|
|
|
|
char *end = fs->value + line[current].end;
|
2006-05-06 16:36:48 -04:00
|
|
|
int cells = 0;
|
2006-01-14 16:44:00 -05:00
|
|
|
|
2006-05-06 16:36:48 -04:00
|
|
|
while(cells < max_cells) {
|
2006-09-17 09:06:22 -04:00
|
|
|
unicode_val_T data = utf8_to_unicode(&text, end);
|
2006-01-14 16:44:00 -05:00
|
|
|
|
|
|
|
if (data == UCS_NO_CHAR) break;
|
2006-05-06 16:36:48 -04:00
|
|
|
cells += unicode_to_cell(data);
|
2006-01-14 16:44:00 -05:00
|
|
|
}
|
|
|
|
fs->state = (int)(text - fs->value);
|
|
|
|
}
|
2006-09-17 09:12:47 -04:00
|
|
|
#endif /* CONFIG_UTF8 */
|
2006-01-14 16:44:00 -05:00
|
|
|
|
|
|
|
static int
|
2006-09-17 09:12:47 -04:00
|
|
|
#ifdef CONFIG_UTF8
|
2006-01-14 16:44:00 -05:00
|
|
|
do_op_home(struct form_state *fs, struct line_info *line, int current, int utf8)
|
2006-02-02 18:27:01 -05:00
|
|
|
#else
|
|
|
|
do_op_home(struct form_state *fs, struct line_info *line, int current)
|
2006-09-17 09:12:47 -04:00
|
|
|
#endif /* CONFIG_UTF8 */
|
2005-09-15 09:58:31 -04:00
|
|
|
{
|
2006-05-06 16:36:48 -04:00
|
|
|
if (current == -1)
|
|
|
|
return 0;
|
2006-09-17 09:12:47 -04:00
|
|
|
#ifdef CONFIG_UTF8
|
2006-05-06 16:36:48 -04:00
|
|
|
if (utf8)
|
|
|
|
fs->state = line[current - !!fs->state_cell].start;
|
|
|
|
else
|
2006-09-17 09:12:47 -04:00
|
|
|
#endif /* CONFIG_UTF8 */
|
2006-05-06 16:36:48 -04:00
|
|
|
fs->state = line[current].start;
|
2005-09-15 09:58:31 -04:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2006-09-17 09:12:47 -04:00
|
|
|
#ifdef CONFIG_UTF8
|
2006-05-06 16:36:48 -04:00
|
|
|
static int
|
2006-01-14 16:44:00 -05:00
|
|
|
do_op_up(struct form_state *fs, struct line_info *line, int current, int utf8)
|
2005-09-15 09:58:31 -04:00
|
|
|
{
|
2006-07-27 03:49:49 -04:00
|
|
|
int old_state;
|
2006-07-27 03:51:10 -04:00
|
|
|
|
2005-09-15 09:58:31 -04:00
|
|
|
if (current == -1) return 0;
|
|
|
|
|
2006-05-06 16:36:48 -04:00
|
|
|
if (!(current - !!fs->state_cell)) return 1;
|
2006-01-14 16:44:00 -05:00
|
|
|
|
2006-05-06 16:36:48 -04:00
|
|
|
if (!utf8) {
|
|
|
|
fs->state -= line[current].start - line[current-1].start;
|
|
|
|
int_upper_bound(&fs->state, line[current-1].end);
|
2006-01-14 16:44:00 -05:00
|
|
|
return 0;
|
|
|
|
}
|
2006-05-06 16:36:48 -04:00
|
|
|
|
2006-07-27 03:49:49 -04:00
|
|
|
old_state = fs->state;
|
2006-05-06 16:36:48 -04:00
|
|
|
if (fs->state_cell) {
|
|
|
|
int len = utf8_ptr2cells(fs->value + line[current - 1].start,
|
|
|
|
fs->value + fs->state_cell);
|
|
|
|
|
|
|
|
new_pos(fs, line, current - 2, len + line[current - 1].last_char_width);
|
|
|
|
} else {
|
|
|
|
int len = utf8_ptr2cells(fs->value + line[current].start,
|
|
|
|
fs->value + fs->state);
|
|
|
|
|
|
|
|
new_pos(fs, line, current - 1, len);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (old_state != fs->state ) {
|
|
|
|
if (fs->state_cell && fs->state == line[current - 1].start) {
|
2021-01-02 10:20:27 -05:00
|
|
|
char *new_value;
|
2006-05-06 16:36:48 -04:00
|
|
|
|
|
|
|
new_value = utf8_prevchar(fs->value + fs->state, 1, fs->value);
|
|
|
|
fs->state_cell = new_value - fs->value;
|
|
|
|
} else
|
|
|
|
fs->state_cell = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
#else
|
|
|
|
|
|
|
|
static int
|
|
|
|
do_op_up(struct form_state *fs, struct line_info *line, int current)
|
|
|
|
{
|
|
|
|
if (current == -1) return 0;
|
|
|
|
if (!current) return 1;
|
2006-01-14 16:44:00 -05:00
|
|
|
|
2005-09-15 09:58:31 -04:00
|
|
|
fs->state -= line[current].start - line[current-1].start;
|
|
|
|
int_upper_bound(&fs->state, line[current-1].end);
|
|
|
|
return 0;
|
|
|
|
}
|
2006-09-17 09:12:47 -04:00
|
|
|
#endif /* CONFIG_UTF8 */
|
2005-09-15 09:58:31 -04:00
|
|
|
|
2006-09-17 09:12:47 -04:00
|
|
|
#ifdef CONFIG_UTF8
|
2006-05-06 16:36:48 -04:00
|
|
|
static int
|
2006-01-14 16:44:00 -05:00
|
|
|
do_op_down(struct form_state *fs, struct line_info *line, int current, int utf8)
|
2005-09-15 09:58:31 -04:00
|
|
|
{
|
2006-07-27 03:49:49 -04:00
|
|
|
int old_state;
|
|
|
|
|
2005-09-15 09:58:31 -04:00
|
|
|
if (current == -1) return 0;
|
|
|
|
|
2006-05-06 16:36:48 -04:00
|
|
|
if (line[current + 1 - !!fs->state_cell].start == -1) return 1;
|
2006-01-14 16:44:00 -05:00
|
|
|
|
2006-05-06 16:36:48 -04:00
|
|
|
if (!utf8) {
|
|
|
|
fs->state += line[current+1].start - line[current].start;
|
|
|
|
int_upper_bound(&fs->state, line[current+1].end);
|
2006-01-14 16:44:00 -05:00
|
|
|
return 0;
|
|
|
|
}
|
2006-05-06 16:36:48 -04:00
|
|
|
|
2006-07-27 03:49:49 -04:00
|
|
|
old_state = fs->state;
|
2006-05-06 16:36:48 -04:00
|
|
|
if (fs->state_cell) {
|
|
|
|
int len = utf8_ptr2cells(fs->value + line[current - 1].start,
|
|
|
|
fs->value + fs->state_cell);
|
|
|
|
|
|
|
|
new_pos(fs, line, current, len + line[current - 1].last_char_width);
|
|
|
|
} else {
|
|
|
|
int len = utf8_ptr2cells(fs->value + line[current].start,
|
|
|
|
fs->value + fs->state);
|
|
|
|
|
|
|
|
new_pos(fs, line, current + 1, len);
|
|
|
|
}
|
|
|
|
if (old_state != fs->state ) {
|
|
|
|
if (fs->state_cell && fs->state == line[current+1].start) {
|
2021-01-02 10:20:27 -05:00
|
|
|
char *new_value;
|
2006-05-06 16:36:48 -04:00
|
|
|
|
|
|
|
new_value = utf8_prevchar(fs->value + fs->state, 1, fs->value);
|
|
|
|
fs->state_cell = new_value - fs->value;
|
|
|
|
} else
|
|
|
|
fs->state_cell = 0;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
#else
|
|
|
|
|
|
|
|
static int
|
|
|
|
do_op_down(struct form_state *fs, struct line_info *line, int current)
|
|
|
|
{
|
|
|
|
if (current == -1) return 0;
|
|
|
|
if (line[current+1].start == -1) return 1;
|
2006-02-02 18:27:01 -05:00
|
|
|
|
2005-09-15 09:58:31 -04:00
|
|
|
fs->state += line[current+1].start - line[current].start;
|
|
|
|
int_upper_bound(&fs->state, line[current+1].end);
|
|
|
|
return 0;
|
|
|
|
}
|
2006-09-17 09:12:47 -04:00
|
|
|
#endif /* CONFIG_UTF8 */
|
2005-09-15 09:58:31 -04:00
|
|
|
|
2006-09-17 09:12:47 -04:00
|
|
|
#ifdef CONFIG_UTF8
|
2006-05-06 16:36:48 -04:00
|
|
|
static int
|
2006-01-14 16:44:00 -05:00
|
|
|
do_op_end(struct form_state *fs, struct line_info *line, int current, int utf8)
|
2006-05-06 16:36:48 -04:00
|
|
|
{
|
|
|
|
if (current == -1) {
|
|
|
|
fs->state = strlen(fs->value);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!utf8) {
|
|
|
|
int wrap = line[current + 1].start == line[current].end;
|
|
|
|
|
|
|
|
/* Don't jump to next line when wrapping. */
|
|
|
|
fs->state = int_max(0, line[current].end - wrap);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
current -= !!fs->state_cell;
|
|
|
|
fs->state = line[current].end;
|
|
|
|
if (line[current].split_next) {
|
2021-01-02 10:20:27 -05:00
|
|
|
char *new_value;
|
2006-05-06 16:36:48 -04:00
|
|
|
|
|
|
|
new_value = utf8_prevchar(fs->value + fs->state, 1, fs->value);
|
|
|
|
fs->state_cell = new_value - fs->value;
|
|
|
|
} else {
|
|
|
|
fs->state_cell = 0;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2006-02-02 18:27:01 -05:00
|
|
|
#else
|
2006-05-06 16:36:48 -04:00
|
|
|
|
|
|
|
static int
|
2006-02-02 18:27:01 -05:00
|
|
|
do_op_end(struct form_state *fs, struct line_info *line, int current)
|
2005-09-15 09:58:31 -04:00
|
|
|
{
|
|
|
|
if (current == -1) {
|
|
|
|
fs->state = strlen(fs->value);
|
|
|
|
|
|
|
|
} else {
|
|
|
|
int wrap = line[current + 1].start == line[current].end;
|
|
|
|
|
|
|
|
/* Don't jump to next line when wrapping. */
|
|
|
|
fs->state = int_max(0, line[current].end - wrap);
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
2006-09-17 09:12:47 -04:00
|
|
|
#endif /* CONFIG_UTF8 */
|
2005-09-15 09:58:31 -04:00
|
|
|
|
|
|
|
static int
|
2006-09-17 09:12:47 -04:00
|
|
|
#ifdef CONFIG_UTF8
|
2006-01-14 16:44:00 -05:00
|
|
|
do_op_bob(struct form_state *fs, struct line_info *line, int current, int utf8)
|
2006-02-02 18:27:01 -05:00
|
|
|
#else
|
|
|
|
do_op_bob(struct form_state *fs, struct line_info *line, int current)
|
2006-09-17 09:12:47 -04:00
|
|
|
#endif /* CONFIG_UTF8 */
|
2005-09-15 09:58:31 -04:00
|
|
|
{
|
|
|
|
if (current == -1) return 0;
|
|
|
|
|
|
|
|
fs->state -= line[current].start;
|
|
|
|
int_upper_bound(&fs->state, line[0].end);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
2006-09-17 09:12:47 -04:00
|
|
|
#ifdef CONFIG_UTF8
|
2006-01-14 16:44:00 -05:00
|
|
|
do_op_eob(struct form_state *fs, struct line_info *line, int current, int utf8)
|
2006-02-02 18:27:01 -05:00
|
|
|
#else
|
|
|
|
do_op_eob(struct form_state *fs, struct line_info *line, int current)
|
2006-09-17 09:12:47 -04:00
|
|
|
#endif /* CONFIG_UTF8 */
|
2005-09-15 09:58:31 -04:00
|
|
|
{
|
|
|
|
if (current == -1) {
|
|
|
|
fs->state = strlen(fs->value);
|
|
|
|
|
|
|
|
} else {
|
|
|
|
int last = get_textarea_line_number(line, strlen(fs->value));
|
|
|
|
|
|
|
|
assertm(last != -1, "line info corrupt");
|
|
|
|
|
|
|
|
fs->state += line[last].start - line[current].start;
|
|
|
|
int_upper_bound(&fs->state, line[last].end);
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2006-09-17 09:12:47 -04:00
|
|
|
#ifdef CONFIG_UTF8
|
2005-09-15 09:58:31 -04:00
|
|
|
enum frame_event_status
|
2018-09-09 13:18:53 -04:00
|
|
|
textarea_op_home(struct form_state *fs, struct el_form_control *fc, int utf8)
|
2005-09-15 09:58:31 -04:00
|
|
|
{
|
2006-01-14 16:44:00 -05:00
|
|
|
return textarea_op(fs, fc, utf8, do_op_home);
|
2005-09-15 09:58:31 -04:00
|
|
|
}
|
2006-02-02 18:27:01 -05:00
|
|
|
#else
|
|
|
|
enum frame_event_status
|
2018-09-09 13:18:53 -04:00
|
|
|
textarea_op_home(struct form_state *fs, struct el_form_control *fc)
|
2006-02-02 18:27:01 -05:00
|
|
|
{
|
|
|
|
return textarea_op(fs, fc, do_op_home);
|
|
|
|
}
|
2006-09-17 09:12:47 -04:00
|
|
|
#endif /* CONFIG_UTF8 */
|
2005-09-15 09:58:31 -04:00
|
|
|
|
2006-09-17 09:12:47 -04:00
|
|
|
#ifdef CONFIG_UTF8
|
2005-09-15 09:58:31 -04:00
|
|
|
enum frame_event_status
|
2018-09-09 13:18:53 -04:00
|
|
|
textarea_op_up(struct form_state *fs, struct el_form_control *fc, int utf8)
|
2005-09-15 09:58:31 -04:00
|
|
|
{
|
2006-01-14 16:44:00 -05:00
|
|
|
return textarea_op(fs, fc, utf8, do_op_up);
|
2005-09-15 09:58:31 -04:00
|
|
|
}
|
2006-02-02 18:27:01 -05:00
|
|
|
#else
|
|
|
|
enum frame_event_status
|
2018-09-09 13:18:53 -04:00
|
|
|
textarea_op_up(struct form_state *fs, struct el_form_control *fc)
|
2006-02-02 18:27:01 -05:00
|
|
|
{
|
|
|
|
return textarea_op(fs, fc, do_op_up);
|
|
|
|
}
|
2006-09-17 09:12:47 -04:00
|
|
|
#endif /* CONFIG_UTF8 */
|
2005-09-15 09:58:31 -04:00
|
|
|
|
2006-09-17 09:12:47 -04:00
|
|
|
#ifdef CONFIG_UTF8
|
2005-09-15 09:58:31 -04:00
|
|
|
enum frame_event_status
|
2018-09-09 13:18:53 -04:00
|
|
|
textarea_op_down(struct form_state *fs, struct el_form_control *fc, int utf8)
|
2005-09-15 09:58:31 -04:00
|
|
|
{
|
2006-01-14 16:44:00 -05:00
|
|
|
return textarea_op(fs, fc, utf8, do_op_down);
|
2005-09-15 09:58:31 -04:00
|
|
|
}
|
2006-02-02 18:27:01 -05:00
|
|
|
#else
|
|
|
|
enum frame_event_status
|
2018-09-09 13:18:53 -04:00
|
|
|
textarea_op_down(struct form_state *fs, struct el_form_control *fc)
|
2006-02-02 18:27:01 -05:00
|
|
|
{
|
|
|
|
return textarea_op(fs, fc, do_op_down);
|
|
|
|
}
|
2006-09-17 09:12:47 -04:00
|
|
|
#endif /* CONFIG_UTF8 */
|
2005-09-15 09:58:31 -04:00
|
|
|
|
2006-09-17 09:12:47 -04:00
|
|
|
#ifdef CONFIG_UTF8
|
2005-09-15 09:58:31 -04:00
|
|
|
enum frame_event_status
|
2018-09-09 13:18:53 -04:00
|
|
|
textarea_op_end(struct form_state *fs, struct el_form_control *fc, int utf8)
|
2005-09-15 09:58:31 -04:00
|
|
|
{
|
2006-01-14 16:44:00 -05:00
|
|
|
return textarea_op(fs, fc, utf8, do_op_end);
|
2005-09-15 09:58:31 -04:00
|
|
|
}
|
2006-02-02 18:27:01 -05:00
|
|
|
#else
|
|
|
|
enum frame_event_status
|
2018-09-09 13:18:53 -04:00
|
|
|
textarea_op_end(struct form_state *fs, struct el_form_control *fc)
|
2006-02-02 18:27:01 -05:00
|
|
|
{
|
|
|
|
return textarea_op(fs, fc, do_op_end);
|
|
|
|
}
|
2006-09-17 09:12:47 -04:00
|
|
|
#endif /* CONFIG_UTF8 */
|
2005-09-15 09:58:31 -04:00
|
|
|
|
|
|
|
/* Set the form state so the cursor is on the first line of the buffer.
|
|
|
|
* Preserve the column if possible. */
|
2006-09-17 09:12:47 -04:00
|
|
|
#ifdef CONFIG_UTF8
|
2005-09-15 09:58:31 -04:00
|
|
|
enum frame_event_status
|
2018-09-09 13:18:53 -04:00
|
|
|
textarea_op_bob(struct form_state *fs, struct el_form_control *fc, int utf8)
|
2005-09-15 09:58:31 -04:00
|
|
|
{
|
2006-01-14 16:44:00 -05:00
|
|
|
return textarea_op(fs, fc, utf8, do_op_bob);
|
2005-09-15 09:58:31 -04:00
|
|
|
}
|
2006-02-02 18:27:01 -05:00
|
|
|
#else
|
|
|
|
enum frame_event_status
|
2018-09-09 13:18:53 -04:00
|
|
|
textarea_op_bob(struct form_state *fs, struct el_form_control *fc)
|
2006-02-02 18:27:01 -05:00
|
|
|
{
|
|
|
|
return textarea_op(fs, fc, do_op_bob);
|
|
|
|
}
|
2006-09-17 09:12:47 -04:00
|
|
|
#endif /* CONFIG_UTF8 */
|
2005-09-15 09:58:31 -04:00
|
|
|
|
2007-07-27 07:13:27 -04:00
|
|
|
/** Set the form state so the cursor is on the last line of the buffer. Preserve
|
2005-09-15 09:58:31 -04:00
|
|
|
* the column if possible. This is done by getting current and last line and
|
|
|
|
* then shifting the state by the delta of both lines start position bounding
|
|
|
|
* the whole thing to the end of the last line. */
|
2006-09-17 09:12:47 -04:00
|
|
|
#ifdef CONFIG_UTF8
|
2005-09-15 09:58:31 -04:00
|
|
|
enum frame_event_status
|
2018-09-09 13:18:53 -04:00
|
|
|
textarea_op_eob(struct form_state *fs, struct el_form_control *fc, int utf8)
|
2005-09-15 09:58:31 -04:00
|
|
|
{
|
2006-01-14 16:44:00 -05:00
|
|
|
return textarea_op(fs, fc, utf8, do_op_eob);
|
2005-09-15 09:58:31 -04:00
|
|
|
}
|
2006-02-02 18:27:01 -05:00
|
|
|
#else
|
|
|
|
enum frame_event_status
|
2018-09-09 13:18:53 -04:00
|
|
|
textarea_op_eob(struct form_state *fs, struct el_form_control *fc)
|
2006-02-02 18:27:01 -05:00
|
|
|
{
|
|
|
|
return textarea_op(fs, fc, do_op_eob);
|
|
|
|
}
|
2006-09-17 09:12:47 -04:00
|
|
|
#endif /* CONFIG_UTF8 */
|
2005-09-15 09:58:31 -04:00
|
|
|
|
|
|
|
enum frame_event_status
|
2006-09-17 09:12:47 -04:00
|
|
|
#ifdef CONFIG_UTF8
|
2018-09-09 13:18:53 -04:00
|
|
|
textarea_op_enter(struct form_state *fs, struct el_form_control *fc, int utf8)
|
2006-02-02 18:27:01 -05:00
|
|
|
#else
|
2018-09-09 13:18:53 -04:00
|
|
|
textarea_op_enter(struct form_state *fs, struct el_form_control *fc)
|
2006-09-17 09:12:47 -04:00
|
|
|
#endif /* CONFIG_UTF8 */
|
2005-09-15 09:58:31 -04:00
|
|
|
{
|
|
|
|
assert(fs && fs->value && fc);
|
|
|
|
if_assert_failed return FRAME_EVENT_OK;
|
|
|
|
|
|
|
|
if (form_field_is_readonly(fc)
|
|
|
|
|| strlen(fs->value) >= fc->maxlength
|
|
|
|
|| !insert_in_string(&fs->value, fs->state, "\n", 1))
|
|
|
|
return FRAME_EVENT_OK;
|
|
|
|
|
|
|
|
fs->state++;
|
|
|
|
return FRAME_EVENT_REFRESH;
|
|
|
|
}
|
|
|
|
|
2006-09-17 09:12:47 -04:00
|
|
|
#ifdef CONFIG_UTF8
|
2006-05-06 16:36:48 -04:00
|
|
|
static int
|
|
|
|
do_op_left(struct form_state *fs, struct line_info *line, int current, int utf8)
|
|
|
|
{
|
2006-07-27 03:49:49 -04:00
|
|
|
int old_state;
|
|
|
|
int new_state;
|
2021-01-02 10:20:27 -05:00
|
|
|
char *new_value;
|
2006-07-27 03:49:49 -04:00
|
|
|
|
2006-05-06 16:36:48 -04:00
|
|
|
if (!utf8) {
|
|
|
|
fs->state = int_max(fs->state - 1, 0);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (fs->state_cell) {
|
|
|
|
fs->state = fs->state_cell;
|
|
|
|
fs->state_cell = 0;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2006-07-27 03:49:49 -04:00
|
|
|
old_state = fs->state;
|
2006-05-06 16:36:48 -04:00
|
|
|
new_value = utf8_prevchar(fs->value + fs->state, 1, fs->value);
|
|
|
|
new_state = new_value - fs->value;
|
|
|
|
|
|
|
|
if (old_state != new_state) {
|
|
|
|
if (old_state == line[current].start && line[current].split_prev)
|
|
|
|
fs->state_cell = new_state;
|
|
|
|
else
|
|
|
|
fs->state = new_state;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
do_op_right(struct form_state *fs, struct line_info *line, int current, int utf8)
|
|
|
|
{
|
2021-01-02 10:20:27 -05:00
|
|
|
char *text, *end;
|
2006-07-27 03:49:49 -04:00
|
|
|
int old_state;
|
|
|
|
|
2006-05-06 16:36:48 -04:00
|
|
|
if (!utf8) {
|
|
|
|
/* TODO: zle */
|
|
|
|
fs->state = int_min(fs->state + 1, strlen(fs->value));
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (fs->state_cell) {
|
|
|
|
fs->state_cell = 0;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2006-07-27 03:49:49 -04:00
|
|
|
text = fs->value + fs->state;
|
2022-01-18 14:30:48 -05:00
|
|
|
end = strchr(text, '\0');
|
2006-07-27 03:49:49 -04:00
|
|
|
old_state = fs->state;
|
2006-09-17 09:06:22 -04:00
|
|
|
utf8_to_unicode(&text, end);
|
2006-05-06 16:36:48 -04:00
|
|
|
|
|
|
|
fs->state = text - fs->value;
|
|
|
|
|
|
|
|
if (old_state != fs->state && line[current].split_next) {
|
|
|
|
fs->state_cell = (fs->state == line[current].end) ? old_state:0;
|
|
|
|
} else if (!line[current].split_next) {
|
|
|
|
fs->state_cell = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
2006-09-17 09:12:47 -04:00
|
|
|
#endif /* CONFIG_UTF8 */
|
2006-05-06 16:36:48 -04:00
|
|
|
|
2006-09-17 09:12:47 -04:00
|
|
|
#ifdef CONFIG_UTF8
|
2006-05-06 16:36:48 -04:00
|
|
|
enum frame_event_status
|
2018-09-09 13:18:53 -04:00
|
|
|
textarea_op_left(struct form_state *fs, struct el_form_control *fc, int utf8)
|
2006-05-06 16:36:48 -04:00
|
|
|
{
|
|
|
|
return textarea_op(fs, fc, utf8, do_op_left);
|
|
|
|
}
|
|
|
|
|
|
|
|
enum frame_event_status
|
2018-09-09 13:18:53 -04:00
|
|
|
textarea_op_right(struct form_state *fs, struct el_form_control *fc, int utf8)
|
2006-05-06 16:36:48 -04:00
|
|
|
{
|
|
|
|
return textarea_op(fs, fc, utf8, do_op_right);
|
|
|
|
}
|
2006-09-17 09:12:47 -04:00
|
|
|
#endif /* CONFIG_UTF8 */
|
2005-09-15 09:58:31 -04:00
|
|
|
|
|
|
|
void
|
|
|
|
set_textarea(struct document_view *doc_view, int direction)
|
|
|
|
{
|
2018-09-09 13:18:53 -04:00
|
|
|
struct el_form_control *fc;
|
2005-09-15 09:58:31 -04:00
|
|
|
struct form_state *fs;
|
|
|
|
struct link *link;
|
2006-09-17 09:12:47 -04:00
|
|
|
#ifdef CONFIG_UTF8
|
2006-01-14 16:44:00 -05:00
|
|
|
int utf8 = doc_view->document->options.utf8;
|
2006-09-17 09:12:47 -04:00
|
|
|
#endif /* CONFIG_UTF8 */
|
2005-09-15 09:58:31 -04:00
|
|
|
|
|
|
|
assert(doc_view && doc_view->vs && doc_view->document);
|
|
|
|
assert(direction == 1 || direction == -1);
|
|
|
|
if_assert_failed return;
|
|
|
|
|
|
|
|
link = get_current_link(doc_view);
|
|
|
|
if (!link || link->type != LINK_AREA)
|
|
|
|
return;
|
|
|
|
|
|
|
|
fc = get_link_form_control(link);
|
2007-03-11 06:22:02 -04:00
|
|
|
assertm(fc != NULL, "link has no form control");
|
2005-09-15 09:58:31 -04:00
|
|
|
if_assert_failed return;
|
|
|
|
|
|
|
|
if (fc->mode == FORM_MODE_DISABLED) return;
|
|
|
|
|
|
|
|
fs = find_form_state(doc_view, fc);
|
|
|
|
if (!fs || !fs->value) return;
|
|
|
|
|
|
|
|
/* Depending on which way we entered the textarea move cursor so that
|
|
|
|
* it is available at end or start. */
|
2006-09-17 09:12:47 -04:00
|
|
|
#ifdef CONFIG_UTF8
|
2005-09-15 09:58:31 -04:00
|
|
|
if (direction == 1)
|
2006-01-14 16:44:00 -05:00
|
|
|
textarea_op_eob(fs, fc, utf8);
|
2005-09-15 09:58:31 -04:00
|
|
|
else
|
2006-01-14 16:44:00 -05:00
|
|
|
textarea_op_bob(fs, fc, utf8);
|
2006-02-02 18:27:01 -05:00
|
|
|
#else
|
|
|
|
if (direction == 1)
|
|
|
|
textarea_op_eob(fs, fc);
|
|
|
|
else
|
|
|
|
textarea_op_bob(fs, fc);
|
2006-09-17 09:12:47 -04:00
|
|
|
#endif /* CONFIG_UTF8 */
|
2005-09-15 09:58:31 -04:00
|
|
|
}
|