#include <sys/cdefs.h>
__RCSID("$NetBSD: field.c,v 1.32 2021/04/13 13:13:03 christos Exp $");
#include <sys/param.h>
#include <stdlib.h>
#include <strings.h>
#include <stdarg.h>
#include <form.h>
#include "internals.h"
extern FORM _formi_default_form;
FIELD _formi_default_field = {
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
FALSE,
NO_JUSTIFICATION,
FALSE,
NULL,
0,
NULL,
0,
0,
0,
0,
0,
0,
A_NORMAL,
A_NORMAL,
' ',
DEFAULT_FORM_OPTS,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
{NULL, NULL},
NULL,
NULL,
NULL,
NULL,
};
static int
field_buffer_init(FIELD *field, int buffer, unsigned int len);
static FIELD *
_formi_create_field(FIELD *, int, int, int, int, int, int);
int
set_field_userptr(FIELD *field, void *ptr)
{
FIELD *fp = (field == NULL) ? &_formi_default_field : field;
fp->userptr = ptr;
return E_OK;
}
void *
field_userptr(FIELD *field)
{
if (field == NULL)
return _formi_default_field.userptr;
else
return field->userptr;
}
int
set_field_opts(FIELD *field, Form_Options options)
{
int i;
FIELD *fp = (field == NULL) ? &_formi_default_field : field;
if ((field != NULL) && (field->parent != NULL) &&
(field->parent->cur_field == field->index))
return E_CURRENT;
if ((options & O_STATIC) == O_STATIC) {
for (i = 0; i < fp->nbuf; i++) {
if (fp->buffers[i].length > fp->cols)
fp->buffers[i].string[fp->cols] = '\0';
}
}
fp->opts = options;
if ((field != NULL) && (field->parent != NULL)
&& (field->parent->posted == 1)) {
_formi_redraw_field(field->parent, field->index);
pos_form_cursor(field->parent);
wrefresh(field->parent->scrwin);
}
return E_OK;
}
int
field_opts_on(FIELD *field, Form_Options options)
{
int i;
FIELD *fp = (field == NULL) ? &_formi_default_field : field;
if ((field != NULL) && (field->parent != NULL) &&
(field->parent->cur_field == field->index))
return E_CURRENT;
if ((options & O_STATIC) == O_STATIC) {
for (i = 0; i < fp->nbuf; i++) {
if (fp->buffers[i].length > fp->cols)
fp->buffers[i].string[fp->cols] = '\0';
}
}
fp->opts |= options;
if ((field != NULL) && (field->parent != NULL)
&& (field->parent->posted == 1)) {
_formi_redraw_field(field->parent, field->index);
pos_form_cursor(field->parent);
wrefresh(field->parent->scrwin);
}
return E_OK;
}
int
field_opts_off(FIELD *field, Form_Options options)
{
FIELD *fp = (field == NULL) ? &_formi_default_field : field;
if ((field != NULL) && (field->parent != NULL) &&
(field->parent->cur_field == field->index))
return E_CURRENT;
fp->opts &= ~options;
if ((field != NULL) && (field->parent != NULL)
&& (field->parent->posted == 1)) {
_formi_redraw_field(field->parent, field->index);
pos_form_cursor(field->parent);
wrefresh(field->parent->scrwin);
}
return E_OK;
}
Form_Options
field_opts(FIELD *field)
{
if (field == NULL)
return _formi_default_field.opts;
else
return field->opts;
}
int
set_field_just(FIELD *field, int justification)
{
FIELD *fp = (field == NULL) ? &_formi_default_field : field;
if ((field != NULL) && (field->parent != NULL) &&
(field->parent->cur_field == field->index))
return E_CURRENT;
if ((justification < MIN_JUST_STYLE)
|| (justification > MAX_JUST_STYLE))
return E_BAD_ARGUMENT;
if (((fp->opts & O_STATIC) != O_STATIC) ||
((fp->rows + fp->nrows) > 1))
return E_BAD_ARGUMENT;
fp->justification = justification;
_formi_init_field_xpos(fp);
return E_OK;
}
int
field_just(FIELD *field)
{
if (field == NULL)
return _formi_default_field.justification;
else
return field->justification;
}
int
field_info(FIELD *field, int *rows, int *cols, int *frow, int *fcol,
int *nrow, int *nbuf)
{
if (field == NULL)
return E_BAD_ARGUMENT;
*rows = field->rows;
*cols = field->cols;
*frow = field->form_row;
*fcol = field->form_col;
*nrow = field->nrows;
*nbuf = field->nbuf;
return E_OK;
}
int
dynamic_field_info(FIELD *field, int *drows, int *dcols, int *max)
{
if (field == NULL)
return E_BAD_ARGUMENT;
if ((field->opts & O_STATIC) == O_STATIC) {
*drows = field->rows;
*dcols = field->cols;
} else {
*drows = field->drows;
*dcols = field->dcols;
}
*max = field->max;
return E_OK;
}
static int
field_buffer_init(FIELD *field, int buffer, unsigned int len)
{
int status;
char *newp;
if (buffer == 0) {
field->start_char = 0;
field->start_line = 0;
field->row_xpos = 0;
field->cursor_xpos = 0;
field->cursor_ypos = 0;
field->row_count = 1;
field->alines->length = len;
if ((newp = realloc(field->alines->string,
(size_t) len + 1)) == NULL)
return E_SYSTEM_ERROR;
field->alines->string = newp;
field->alines->allocated = len + 1;
strlcpy(field->alines->string, field->buffers[buffer].string,
(size_t) len + 1);
field->alines->expanded =
_formi_tab_expanded_length(field->alines->string,
0, field->alines->length);
field->start_line = field->alines;
field->cur_line = field->alines;
status = _formi_wrap_field(field, field->cur_line);
if (status != E_OK)
return status;
if (field->row_count == 1)
_formi_calculate_tabs(field->alines);
if ((field->parent != NULL) && (field->parent->posted == 1)) {
_formi_redraw_field(field->parent, field->index);
pos_form_cursor(field->parent);
}
}
return E_OK;
}
int
set_field_printf(FIELD *field, int buffer, char *fmt, ...)
{
int len;
va_list args;
if (field == NULL)
return E_BAD_ARGUMENT;
if (buffer >= field->nbuf)
return E_BAD_ARGUMENT;
va_start(args, fmt);
if (field->buffers[buffer].allocated != 0)
free(field->buffers[buffer].string);
len = vasprintf(&field->buffers[buffer].string, fmt, args);
va_end(args);
if (len < 0)
return E_SYSTEM_ERROR;
field->buffers[buffer].length = len;
field->buffers[buffer].allocated = len + 1;
if (((field->opts & O_STATIC) == O_STATIC) && (len > field->cols)
&& ((field->rows + field->nrows) == 1))
len = field->cols;
field->buffers[buffer].string[len] = '\0';
return field_buffer_init(field, buffer, (unsigned int) len);
}
int
set_field_buffer(FIELD *field, int buffer, const char *value)
{
unsigned int len;
int status;
if (field == NULL)
return E_BAD_ARGUMENT;
if (buffer >= field->nbuf)
return E_BAD_ARGUMENT;
len = (unsigned int) strlen(value);
if (((field->opts & O_STATIC) == O_STATIC) && (len > field->cols)
&& ((field->rows + field->nrows) == 1))
len = field->cols;
_formi_dbg_printf( "%s: len = %d, value = %s, buffer=%d\n", __func__,
len, value, buffer);
if (field->buffers[buffer].string != NULL)
_formi_dbg_printf("%s: string=%s, len = %d\n", __func__,
field->buffers[buffer].string,
field->buffers[buffer].length);
else
_formi_dbg_printf("%s: string=(null), len = 0\n", __func__);
_formi_dbg_printf("%s: lines.len = %d\n", __func__,
field->alines[0].length);
if ((field->buffers[buffer].string = realloc(
field->buffers[buffer].string, (size_t) len + 1)) == NULL)
return E_SYSTEM_ERROR;
strlcpy(field->buffers[buffer].string, value, (size_t) len + 1);
field->buffers[buffer].length = len;
field->buffers[buffer].allocated = len + 1;
status = field_buffer_init(field, buffer, len);
_formi_dbg_printf("%s: len = %d, value = %s\n", __func__, len, value);
_formi_dbg_printf("%s: string = %s, len = %d\n", __func__,
field->buffers[buffer].string, field->buffers[buffer].length);
_formi_dbg_printf("%s: lines.len = %d\n", __func__,
field->alines[0].length);
return status;
}
char *
field_buffer(FIELD *field, int buffer)
{
char *reformat, *p;
_FORMI_FIELD_LINES *linep;
size_t bufsize, pos;
if (field == NULL)
return NULL;
if (buffer >= field->nbuf)
return NULL;
if (_formi_sync_buffer(field) != E_OK)
return NULL;
if ((field->opts & O_REFORMAT) != O_REFORMAT)
return field->buffers[buffer].string;
if (field->row_count <= 1)
return strdup(field->buffers[buffer].string);
bufsize = pos = 0;
reformat = NULL;
for (linep = field->alines; linep; linep = linep->next) {
size_t len = strlen(linep->string);
if (len + 1 >= bufsize - pos) {
bufsize += MAX(1024, 2 * len);
p = realloc(reformat, bufsize);
if (p == NULL) {
free(reformat);
return NULL;
}
reformat = p;
}
memcpy(reformat + pos, linep->string, len);
pos += len;
reformat[pos++] = linep->next ? '\n' : '\0';
}
return reformat;
}
int
set_field_status(FIELD *field, int status)
{
if (field == NULL)
return E_BAD_ARGUMENT;
if (status != FALSE)
field->buf0_status = TRUE;
else
field->buf0_status = FALSE;
return E_OK;
}
int
field_status(FIELD *field)
{
if (field == NULL)
return FALSE;
return field->buf0_status;
}
int
set_max_field(FIELD *fptr, int max)
{
FIELD *field = (fptr == NULL)? &_formi_default_field : fptr;
if ((field->opts & O_STATIC) == O_STATIC)
return E_BAD_ARGUMENT;
if (max < 0)
return E_BAD_ARGUMENT;
field->max = max;
return E_OK;
}
int
set_field_fore(FIELD *fptr, chtype attribute)
{
FIELD *field = (fptr == NULL)? &_formi_default_field : fptr;
field->fore = attribute;
return E_OK;
}
chtype
field_fore(FIELD *field)
{
if (field == NULL)
return _formi_default_field.fore;
else
return field->fore;
}
int
set_field_back(FIELD *field, chtype attribute)
{
if (field == NULL)
_formi_default_field.back = attribute;
else
field->back = attribute;
return E_OK;
}
chtype
field_back(FIELD *field)
{
if (field == NULL)
return _formi_default_field.back;
else
return field->back;
}
int
set_field_pad(FIELD *field, int pad)
{
if (field == NULL)
_formi_default_field.pad = pad;
else
field->pad = pad;
return E_OK;
}
int
field_pad(FIELD *field)
{
if (field == NULL)
return _formi_default_field.pad;
else
return field->pad;
}
int
set_field_init(FORM *form, Form_Hook function)
{
if (form == NULL)
_formi_default_form.field_init = function;
else
form->field_init = function;
return E_OK;
}
Form_Hook
field_init(FORM *form)
{
if (form == NULL)
return _formi_default_form.field_init;
else
return form->field_init;
}
int
set_field_term(FORM *form, Form_Hook function)
{
if (form == NULL)
_formi_default_form.field_term = function;
else
form->field_term = function;
return E_OK;
}
Form_Hook
field_term(FORM *form)
{
if (form == NULL)
return _formi_default_form.field_term;
else
return form->field_term;
}
int
set_new_page(FIELD *fptr, int page)
{
FIELD *field = (fptr == NULL)? &_formi_default_field : fptr;
if (field->parent != NULL)
return E_CONNECTED;
field->page_break = (page != FALSE);
return E_OK;
}
int
new_page(FIELD *field)
{
if (field == NULL)
return _formi_default_field.page_break;
else
return field->page_break;
}
int
field_index(FIELD *field)
{
if (field == NULL)
return E_BAD_ARGUMENT;
if (field->parent == NULL)
return E_NOT_CONNECTED;
return field->index;
}
static FIELD *
_formi_create_field(FIELD *prototype, int rows, int cols, int frow,
int fcol, int nrows, int nbuf)
{
FIELD *new;
if ((rows <= 0) || (cols <= 0) || (frow < 0) || (fcol < 0) ||
(nrows < 0) || (nbuf < 0))
return NULL;
if ((new = malloc(sizeof(*new))) == NULL) {
return NULL;
}
memcpy(new, prototype, sizeof(*new));
new->nbuf = nbuf + 1;
new->rows = rows;
new->cols = cols;
new->form_row = frow;
new->form_col = fcol;
new->nrows = nrows;
new->link = new;
return new;
}
FIELD *
new_field(int rows, int cols, int frow, int fcol, int nrows, int nbuf)
{
FIELD *new;
int i;
if ((new = _formi_create_field(&_formi_default_field, rows, cols,
frow, fcol, nrows, nbuf)) == NULL)
return NULL;
if ((new->buffers = calloc(nbuf + 1, sizeof(*new->buffers))) == NULL) {
free(new);
return NULL;
}
for (i = 0; i < nbuf + 1; i++) {
if ((new->buffers[i].string =
malloc(sizeof(*new->buffers[i].string))) == NULL) {
goto out;
}
new->buffers[i].string[0] = '\0';
new->buffers[i].length = 0;
new->buffers[i].allocated = 1;
}
if ((new->alines = malloc(sizeof(*new->alines))) == NULL) {
goto out;
}
new->alines->prev = NULL;
new->alines->next = NULL;
new->alines->allocated = 0;
new->alines->length = 0;
new->alines->expanded = 0;
new->alines->string = NULL;
new->alines->hard_ret = FALSE;
new->alines->tabs = NULL;
new->start_line = new->alines;
new->cur_line = new->alines;
return new;
out:
while (--i >= 0) {
free(new->buffers[i].string);
}
free(new->buffers);
free(new);
return NULL;
}
FIELD *
dup_field(FIELD *field, int frow, int fcol)
{
FIELD *new;
size_t row_len, buf_len;
if (field == NULL)
return NULL;
if ((new = _formi_create_field(field, (int) field->rows,
(int) field->cols,
frow, fcol, (int) field->nrows,
field->nbuf - 1)) == NULL)
return NULL;
row_len = (field->rows + field->nrows + 1) * field->cols;
buf_len = (field->nbuf + 1) * row_len * sizeof(*new->buffers);
if ((new->buffers = malloc(buf_len)) == NULL) {
free(new);
return NULL;
}
memcpy(new->buffers, field->buffers, buf_len);
return new;
}
FIELD *
link_field(FIELD *field, int frow, int fcol)
{
FIELD *new;
if (field == NULL)
return NULL;
if ((new = _formi_create_field(field, (int) field->rows,
(int) field->cols,
frow, fcol, (int) field->nrows,
field->nbuf - 1)) == NULL)
return NULL;
new->link = field->link;
field->link = new;
return new;
}
int
free_field(FIELD *field)
{
FIELD *flink;
unsigned int i;
_formi_tab_t *ts, *nts;
if (field == NULL)
return E_BAD_ARGUMENT;
if (field->parent != NULL)
return E_CONNECTED;
if (field->link == field) {
free(field->buffers);
for (i = 0; i + 1 < field->row_count; i++) {
if (field->alines[i].tabs != NULL) {
ts = field->alines[i].tabs;
while (ts != NULL) {
nts = ts->fwd;
free(ts);
ts = nts;
}
}
}
} else {
for (flink = field->link; flink != field; flink = flink->link);
flink->link = field->link;
}
free(field);
return E_OK;
}