1*0cf98320Schristos /* $NetBSD: field.c,v 1.32 2021/04/13 13:13:03 christos Exp $ */
241859428Sblymn /*-
341859428Sblymn * Copyright (c) 1998-1999 Brett Lymn
441859428Sblymn * (blymn@baea.com.au, brett_lymn@yahoo.com.au)
541859428Sblymn * All rights reserved.
641859428Sblymn *
741859428Sblymn * This code has been donated to The NetBSD Foundation by the Author.
841859428Sblymn *
941859428Sblymn * Redistribution and use in source and binary forms, with or without
1041859428Sblymn * modification, are permitted provided that the following conditions
1141859428Sblymn * are met:
1241859428Sblymn * 1. Redistributions of source code must retain the above copyright
1341859428Sblymn * notice, this list of conditions and the following disclaimer.
1441859428Sblymn * 2. The name of the author may not be used to endorse or promote products
15c03a48d6Swiz * derived from this software without specific prior written permission
1641859428Sblymn *
1741859428Sblymn * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
1841859428Sblymn * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
1941859428Sblymn * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
2041859428Sblymn * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
2141859428Sblymn * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
2241859428Sblymn * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2341859428Sblymn * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2441859428Sblymn * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2541859428Sblymn * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
2641859428Sblymn * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2741859428Sblymn *
2841859428Sblymn *
2941859428Sblymn */
3041859428Sblymn
31a2ed7b2dSlukem #include <sys/cdefs.h>
32*0cf98320Schristos __RCSID("$NetBSD: field.c,v 1.32 2021/04/13 13:13:03 christos Exp $");
33a2ed7b2dSlukem
34cdffa8c1Schristos #include <sys/param.h>
3541859428Sblymn #include <stdlib.h>
3641859428Sblymn #include <strings.h>
37c4f23a93Sblymn #include <stdarg.h>
3841859428Sblymn #include <form.h>
3941859428Sblymn #include "internals.h"
4041859428Sblymn
4141859428Sblymn extern FORM _formi_default_form;
4241859428Sblymn
4341859428Sblymn FIELD _formi_default_field = {
4441859428Sblymn 0, /* rows in the field */
4541859428Sblymn 0, /* columns in the field */
4641859428Sblymn 0, /* dynamic rows */
4741859428Sblymn 0, /* dynamic columns */
4841859428Sblymn 0, /* maximum growth */
4941859428Sblymn 0, /* starting row in the form subwindow */
5041859428Sblymn 0, /* starting column in the form subwindow */
5141859428Sblymn 0, /* number of off screen rows */
5241859428Sblymn 0, /* index of this field in form fields array. */
5341859428Sblymn 0, /* number of buffers associated with this field */
5441859428Sblymn FALSE, /* set to true if buffer 0 has changed. */
5541859428Sblymn NO_JUSTIFICATION, /* justification style of the field */
5641859428Sblymn FALSE, /* set to true if field is in overlay mode */
5719f07fb2Sblymn NULL, /* pointer to the current line cursor is on */
5841859428Sblymn 0, /* starting char in string (horiz scroll) */
5919f07fb2Sblymn NULL, /* starting line in field (vert scroll) */
6041859428Sblymn 0, /* number of rows actually used in field */
61759e545dSblymn 0, /* actual pos of cursor in row, not same as x pos due to tabs */
6241859428Sblymn 0, /* x pos of cursor in field */
6341859428Sblymn 0, /* y pos of cursor in field */
6441859428Sblymn 0, /* start of a new page on the form if 1 */
6541859428Sblymn 0, /* number of the page this field is on */
6641859428Sblymn A_NORMAL, /* character attributes for the foreground */
67c0219226Sblymn A_NORMAL, /* character attributes for the background */
6841859428Sblymn ' ', /* padding character */
6941859428Sblymn DEFAULT_FORM_OPTS, /* options for the field */
7041859428Sblymn NULL, /* the form this field is bound to, if any */
7141859428Sblymn NULL, /* field above this one */
7241859428Sblymn NULL, /* field below this one */
7341859428Sblymn NULL, /* field to the left of this one */
7441859428Sblymn NULL, /* field to the right of this one */
7541859428Sblymn NULL, /* user defined pointer. */
7641859428Sblymn NULL, /* used if fields are linked */
7741859428Sblymn NULL, /* type struct for the field */
7841859428Sblymn {NULL, NULL}, /* circle queue glue for sorting fields */
7941859428Sblymn NULL, /* args for field type. */
807ffbe072Sblymn NULL, /* pointer to the array of lines structures. */
8119f07fb2Sblymn NULL, /* list of lines available for reuse */
8241859428Sblymn NULL, /* array of buffers for the field */
8341859428Sblymn };
8441859428Sblymn
8541859428Sblymn /* internal function prototypes */
86c4f23a93Sblymn static int
8719f07fb2Sblymn field_buffer_init(FIELD *field, int buffer, unsigned int len);
8841859428Sblymn static FIELD *
8941859428Sblymn _formi_create_field(FIELD *, int, int, int, int, int, int);
9041859428Sblymn
9141859428Sblymn
9241859428Sblymn /*
9341859428Sblymn * Set the userptr for the field
9441859428Sblymn */
9541859428Sblymn int
set_field_userptr(FIELD * field,void * ptr)96af28ef95Sblymn set_field_userptr(FIELD *field, void *ptr)
9741859428Sblymn {
9841859428Sblymn FIELD *fp = (field == NULL) ? &_formi_default_field : field;
9941859428Sblymn
10041859428Sblymn fp->userptr = ptr;
10141859428Sblymn
10241859428Sblymn return E_OK;
10341859428Sblymn }
10441859428Sblymn
10541859428Sblymn /*
10641859428Sblymn * Return the userptr for the field.
10741859428Sblymn */
10841859428Sblymn
109af28ef95Sblymn void *
field_userptr(FIELD * field)11041859428Sblymn field_userptr(FIELD *field)
11141859428Sblymn {
11241859428Sblymn if (field == NULL)
11341859428Sblymn return _formi_default_field.userptr;
11441859428Sblymn else
11541859428Sblymn return field->userptr;
11641859428Sblymn }
11741859428Sblymn
11841859428Sblymn /*
11941859428Sblymn * Set the options for the designated field.
12041859428Sblymn */
12141859428Sblymn int
set_field_opts(FIELD * field,Form_Options options)12241859428Sblymn set_field_opts(FIELD *field, Form_Options options)
12341859428Sblymn {
1246c29066dSblymn int i;
1256c29066dSblymn
12641859428Sblymn FIELD *fp = (field == NULL) ? &_formi_default_field : field;
12741859428Sblymn
1286c29066dSblymn /* not allowed to set opts if the field is the current one */
1296c29066dSblymn if ((field != NULL) && (field->parent != NULL) &&
1306c29066dSblymn (field->parent->cur_field == field->index))
1316c29066dSblymn return E_CURRENT;
1326c29066dSblymn
1336c29066dSblymn if ((options & O_STATIC) == O_STATIC) {
134ad3d4120Sblymn for (i = 0; i < fp->nbuf; i++) {
135ad3d4120Sblymn if (fp->buffers[i].length > fp->cols)
136ad3d4120Sblymn fp->buffers[i].string[fp->cols] = '\0';
1376c29066dSblymn }
1386c29066dSblymn }
1396c29066dSblymn
14041859428Sblymn fp->opts = options;
14141859428Sblymn
1428d09f0f7Sblymn /* if appropriate, redraw the field */
1438d09f0f7Sblymn if ((field != NULL) && (field->parent != NULL)
1448d09f0f7Sblymn && (field->parent->posted == 1)) {
1458d09f0f7Sblymn _formi_redraw_field(field->parent, field->index);
1468d09f0f7Sblymn pos_form_cursor(field->parent);
1478d09f0f7Sblymn wrefresh(field->parent->scrwin);
1488d09f0f7Sblymn }
1498d09f0f7Sblymn
15041859428Sblymn return E_OK;
15141859428Sblymn }
15241859428Sblymn
15341859428Sblymn /*
15441859428Sblymn * Turn on the passed field options.
15541859428Sblymn */
15641859428Sblymn int
field_opts_on(FIELD * field,Form_Options options)15741859428Sblymn field_opts_on(FIELD *field, Form_Options options)
15841859428Sblymn {
1596c29066dSblymn int i;
1606c29066dSblymn
16141859428Sblymn FIELD *fp = (field == NULL) ? &_formi_default_field : field;
16241859428Sblymn
1636c29066dSblymn /* not allowed to set opts if the field is the current one */
1646c29066dSblymn if ((field != NULL) && (field->parent != NULL) &&
1656c29066dSblymn (field->parent->cur_field == field->index))
1666c29066dSblymn return E_CURRENT;
1676c29066dSblymn
1686c29066dSblymn if ((options & O_STATIC) == O_STATIC) {
169ad3d4120Sblymn for (i = 0; i < fp->nbuf; i++) {
170ad3d4120Sblymn if (fp->buffers[i].length > fp->cols)
171ad3d4120Sblymn fp->buffers[i].string[fp->cols] = '\0';
1726c29066dSblymn }
1736c29066dSblymn }
1746c29066dSblymn
17541859428Sblymn fp->opts |= options;
17641859428Sblymn
1778d09f0f7Sblymn /* if appropriate, redraw the field */
1788d09f0f7Sblymn if ((field != NULL) && (field->parent != NULL)
1798d09f0f7Sblymn && (field->parent->posted == 1)) {
1808d09f0f7Sblymn _formi_redraw_field(field->parent, field->index);
1818d09f0f7Sblymn pos_form_cursor(field->parent);
1828d09f0f7Sblymn wrefresh(field->parent->scrwin);
1838d09f0f7Sblymn }
1848d09f0f7Sblymn
18541859428Sblymn return E_OK;
18641859428Sblymn }
18741859428Sblymn
18841859428Sblymn /*
18941859428Sblymn * Turn off the passed field options.
19041859428Sblymn */
19141859428Sblymn int
field_opts_off(FIELD * field,Form_Options options)19241859428Sblymn field_opts_off(FIELD *field, Form_Options options)
19341859428Sblymn {
19441859428Sblymn FIELD *fp = (field == NULL) ? &_formi_default_field : field;
19541859428Sblymn
1966c29066dSblymn /* not allowed to set opts if the field is the current one */
1976c29066dSblymn if ((field != NULL) && (field->parent != NULL) &&
1986c29066dSblymn (field->parent->cur_field == field->index))
1996c29066dSblymn return E_CURRENT;
2006c29066dSblymn
20141859428Sblymn fp->opts &= ~options;
2028d09f0f7Sblymn
2038d09f0f7Sblymn /* if appropriate, redraw the field */
2048d09f0f7Sblymn if ((field != NULL) && (field->parent != NULL)
2058d09f0f7Sblymn && (field->parent->posted == 1)) {
2068d09f0f7Sblymn _formi_redraw_field(field->parent, field->index);
2078d09f0f7Sblymn pos_form_cursor(field->parent);
2088d09f0f7Sblymn wrefresh(field->parent->scrwin);
2098d09f0f7Sblymn }
2108d09f0f7Sblymn
21141859428Sblymn return E_OK;
21241859428Sblymn }
21341859428Sblymn
21441859428Sblymn /*
21541859428Sblymn * Return the field options associated with the passed field.
21641859428Sblymn */
21741859428Sblymn Form_Options
field_opts(FIELD * field)21841859428Sblymn field_opts(FIELD *field)
21941859428Sblymn {
22041859428Sblymn if (field == NULL)
22141859428Sblymn return _formi_default_field.opts;
22241859428Sblymn else
22341859428Sblymn return field->opts;
22441859428Sblymn }
22541859428Sblymn
22641859428Sblymn /*
22741859428Sblymn * Set the justification for the passed field.
22841859428Sblymn */
22941859428Sblymn int
set_field_just(FIELD * field,int justification)23041859428Sblymn set_field_just(FIELD *field, int justification)
23141859428Sblymn {
23241859428Sblymn FIELD *fp = (field == NULL) ? &_formi_default_field : field;
23341859428Sblymn
2346c29066dSblymn /*
2356c29066dSblymn * not allowed to set justification if the field is
2366c29066dSblymn * the current one
2376c29066dSblymn */
2386c29066dSblymn if ((field != NULL) && (field->parent != NULL) &&
2396c29066dSblymn (field->parent->cur_field == field->index))
2406c29066dSblymn return E_CURRENT;
2416c29066dSblymn
24241859428Sblymn if ((justification < MIN_JUST_STYLE) /* check justification valid */
24341859428Sblymn || (justification > MAX_JUST_STYLE))
24441859428Sblymn return E_BAD_ARGUMENT;
24541859428Sblymn
246d0d41d9fSblymn /* only allow justification on static, single row fields */
247d0d41d9fSblymn if (((fp->opts & O_STATIC) != O_STATIC) ||
248d0d41d9fSblymn ((fp->rows + fp->nrows) > 1))
249d0d41d9fSblymn return E_BAD_ARGUMENT;
250d0d41d9fSblymn
25141859428Sblymn fp->justification = justification;
252d0d41d9fSblymn
253d0d41d9fSblymn _formi_init_field_xpos(fp);
254d0d41d9fSblymn
25541859428Sblymn return E_OK;
25641859428Sblymn }
25741859428Sblymn
25841859428Sblymn /*
25941859428Sblymn * Return the justification style of the field passed.
26041859428Sblymn */
26141859428Sblymn int
field_just(FIELD * field)26241859428Sblymn field_just(FIELD *field)
26341859428Sblymn {
26441859428Sblymn if (field == NULL)
26541859428Sblymn return _formi_default_field.justification;
26641859428Sblymn else
26741859428Sblymn return field->justification;
26841859428Sblymn }
26941859428Sblymn
27041859428Sblymn /*
27141859428Sblymn * Return information about the field passed.
27241859428Sblymn */
27341859428Sblymn int
field_info(FIELD * field,int * rows,int * cols,int * frow,int * fcol,int * nrow,int * nbuf)27441859428Sblymn field_info(FIELD *field, int *rows, int *cols, int *frow, int *fcol,
27541859428Sblymn int *nrow, int *nbuf)
27641859428Sblymn {
27741859428Sblymn if (field == NULL)
27841859428Sblymn return E_BAD_ARGUMENT;
27941859428Sblymn
28041859428Sblymn *rows = field->rows;
28141859428Sblymn *cols = field->cols;
28241859428Sblymn *frow = field->form_row;
28341859428Sblymn *fcol = field->form_col;
28441859428Sblymn *nrow = field->nrows;
28541859428Sblymn *nbuf = field->nbuf;
28641859428Sblymn
28741859428Sblymn return E_OK;
28841859428Sblymn }
28941859428Sblymn
29041859428Sblymn /*
29141859428Sblymn * Report the dynamic field information.
29241859428Sblymn */
29341859428Sblymn int
dynamic_field_info(FIELD * field,int * drows,int * dcols,int * max)29441859428Sblymn dynamic_field_info(FIELD *field, int *drows, int *dcols, int *max)
29541859428Sblymn {
29641859428Sblymn if (field == NULL)
29741859428Sblymn return E_BAD_ARGUMENT;
29841859428Sblymn
2996c29066dSblymn if ((field->opts & O_STATIC) == O_STATIC) {
3006c29066dSblymn *drows = field->rows;
3016c29066dSblymn *dcols = field->cols;
3026c29066dSblymn } else {
30341859428Sblymn *drows = field->drows;
30441859428Sblymn *dcols = field->dcols;
3056c29066dSblymn }
3066c29066dSblymn
30741859428Sblymn *max = field->max;
30841859428Sblymn
30941859428Sblymn return E_OK;
31041859428Sblymn }
31141859428Sblymn
31241859428Sblymn /*
313c4f23a93Sblymn * Init all the field variables, perform wrapping and other tasks
314c4f23a93Sblymn * after the field buffer is set.
315c4f23a93Sblymn */
316c4f23a93Sblymn static int
field_buffer_init(FIELD * field,int buffer,unsigned int len)31719f07fb2Sblymn field_buffer_init(FIELD *field, int buffer, unsigned int len)
318c4f23a93Sblymn {
319c4f23a93Sblymn int status;
32019f07fb2Sblymn char *newp;
321c4f23a93Sblymn
322c4f23a93Sblymn if (buffer == 0) {
323c4f23a93Sblymn field->start_char = 0;
324c4f23a93Sblymn field->start_line = 0;
325c4f23a93Sblymn field->row_xpos = 0;
326c4f23a93Sblymn field->cursor_xpos = 0;
327c4f23a93Sblymn field->cursor_ypos = 0;
32819f07fb2Sblymn field->row_count = 1; /* must be at least one row XXX need to shift old rows (if any) to free list??? */
32998eb8895Sroy field->alines->length = len;
33098eb8895Sroy if ((newp = realloc(field->alines->string,
3319ea0254bSwiz (size_t) len + 1)) == NULL)
33219f07fb2Sblymn return E_SYSTEM_ERROR;
33398eb8895Sroy field->alines->string = newp;
33498eb8895Sroy field->alines->allocated = len + 1;
33598eb8895Sroy strlcpy(field->alines->string, field->buffers[buffer].string,
3369ea0254bSwiz (size_t) len + 1);
33798eb8895Sroy field->alines->expanded =
33898eb8895Sroy _formi_tab_expanded_length(field->alines->string,
33998eb8895Sroy 0, field->alines->length);
34019f07fb2Sblymn
34198eb8895Sroy field->start_line = field->alines;
34298eb8895Sroy field->cur_line = field->alines;
343c4f23a93Sblymn
344c4f23a93Sblymn /* we have to hope the wrap works - if it does not then the
345c4f23a93Sblymn buffer is pretty much borked */
34619f07fb2Sblymn status = _formi_wrap_field(field, field->cur_line);
347c4f23a93Sblymn if (status != E_OK)
348c4f23a93Sblymn return status;
349c4f23a93Sblymn
350c4f23a93Sblymn /*
351c4f23a93Sblymn * calculate the tabs for a single row field, the
352c4f23a93Sblymn * multiline case is handled when the wrap is done.
353c4f23a93Sblymn */
354c4f23a93Sblymn if (field->row_count == 1)
35598eb8895Sroy _formi_calculate_tabs(field->alines);
356c4f23a93Sblymn
357c4f23a93Sblymn /* redraw the field to reflect the new contents. If the field
358c4f23a93Sblymn * is attached....
359c4f23a93Sblymn */
360c4f23a93Sblymn if ((field->parent != NULL) && (field->parent->posted == 1)) {
361c4f23a93Sblymn _formi_redraw_field(field->parent, field->index);
362c4f23a93Sblymn /* make sure cursor goes back to current field */
363c4f23a93Sblymn pos_form_cursor(field->parent);
364c4f23a93Sblymn }
365c4f23a93Sblymn }
366c4f23a93Sblymn
367c4f23a93Sblymn return E_OK;
368c4f23a93Sblymn }
369c4f23a93Sblymn
370c4f23a93Sblymn
371c4f23a93Sblymn /*
372c4f23a93Sblymn * Set the field buffer to the string that results from processing
373c4f23a93Sblymn * the given format (fmt) using sprintf.
374c4f23a93Sblymn */
375c4f23a93Sblymn int
set_field_printf(FIELD * field,int buffer,char * fmt,...)376c4f23a93Sblymn set_field_printf(FIELD *field, int buffer, char *fmt, ...)
377c4f23a93Sblymn {
378c4f23a93Sblymn int len;
379c4f23a93Sblymn va_list args;
380c4f23a93Sblymn
381c4f23a93Sblymn if (field == NULL)
382c4f23a93Sblymn return E_BAD_ARGUMENT;
383c4f23a93Sblymn
384c4f23a93Sblymn if (buffer >= field->nbuf)
385c4f23a93Sblymn return E_BAD_ARGUMENT;
386c4f23a93Sblymn
387c4f23a93Sblymn va_start(args, fmt);
388c4f23a93Sblymn /* check for buffer already existing, free the storage */
389c4f23a93Sblymn if (field->buffers[buffer].allocated != 0)
390c4f23a93Sblymn free(field->buffers[buffer].string);
391c4f23a93Sblymn
392c4f23a93Sblymn len = vasprintf(&field->buffers[buffer].string, fmt, args);
393c4f23a93Sblymn va_end(args);
394c4f23a93Sblymn if (len < 0)
395c4f23a93Sblymn return E_SYSTEM_ERROR;
396c4f23a93Sblymn
397c4f23a93Sblymn field->buffers[buffer].length = len;
398c4f23a93Sblymn field->buffers[buffer].allocated = len + 1;
399c4f23a93Sblymn if (((field->opts & O_STATIC) == O_STATIC) && (len > field->cols)
400c4f23a93Sblymn && ((field->rows + field->nrows) == 1))
401c4f23a93Sblymn len = field->cols;
402c4f23a93Sblymn
403c4f23a93Sblymn field->buffers[buffer].string[len] = '\0';
404c4f23a93Sblymn return field_buffer_init(field, buffer, (unsigned int) len);
405c4f23a93Sblymn }
406c4f23a93Sblymn
407c4f23a93Sblymn /*
40841859428Sblymn * Set the value of the field buffer to the value given.
40941859428Sblymn */
41041859428Sblymn
41141859428Sblymn int
set_field_buffer(FIELD * field,int buffer,const char * value)41253ebe243Sjoerg set_field_buffer(FIELD *field, int buffer, const char *value)
41341859428Sblymn {
41419f07fb2Sblymn unsigned int len;
4157ce7b462Sblymn int status;
41641859428Sblymn
41741859428Sblymn if (field == NULL)
41841859428Sblymn return E_BAD_ARGUMENT;
41941859428Sblymn
42041859428Sblymn if (buffer >= field->nbuf) /* make sure buffer is valid */
42141859428Sblymn return E_BAD_ARGUMENT;
42241859428Sblymn
42319f07fb2Sblymn len = (unsigned int) strlen(value);
4247ffbe072Sblymn if (((field->opts & O_STATIC) == O_STATIC) && (len > field->cols)
4257ffbe072Sblymn && ((field->rows + field->nrows) == 1))
4266cda6dc5Sblymn len = field->cols;
4276cda6dc5Sblymn
42823a151b4Schristos _formi_dbg_printf( "%s: len = %d, value = %s, buffer=%d\n", __func__,
429cf202272Sblymn len, value, buffer);
430cf202272Sblymn if (field->buffers[buffer].string != NULL)
43123a151b4Schristos _formi_dbg_printf("%s: string=%s, len = %d\n", __func__,
43223a151b4Schristos field->buffers[buffer].string,
433cf202272Sblymn field->buffers[buffer].length);
434cf202272Sblymn else
43523a151b4Schristos _formi_dbg_printf("%s: string=(null), len = 0\n", __func__);
43623a151b4Schristos _formi_dbg_printf("%s: lines.len = %d\n", __func__,
43798eb8895Sroy field->alines[0].length);
438cf202272Sblymn
43923a151b4Schristos if ((field->buffers[buffer].string = realloc(
44023a151b4Schristos field->buffers[buffer].string, (size_t) len + 1)) == NULL)
44141859428Sblymn return E_SYSTEM_ERROR;
44241859428Sblymn
44319f07fb2Sblymn strlcpy(field->buffers[buffer].string, value, (size_t) len + 1);
44441859428Sblymn field->buffers[buffer].length = len;
44541859428Sblymn field->buffers[buffer].allocated = len + 1;
446c4f23a93Sblymn status = field_buffer_init(field, buffer, len);
447cf202272Sblymn
44823a151b4Schristos _formi_dbg_printf("%s: len = %d, value = %s\n", __func__, len, value);
44923a151b4Schristos _formi_dbg_printf("%s: string = %s, len = %d\n", __func__,
450cf202272Sblymn field->buffers[buffer].string, field->buffers[buffer].length);
45123a151b4Schristos _formi_dbg_printf("%s: lines.len = %d\n", __func__,
45298eb8895Sroy field->alines[0].length);
45341859428Sblymn
454c4f23a93Sblymn return status;
45541859428Sblymn }
45641859428Sblymn
45741859428Sblymn /*
45841859428Sblymn * Return the requested field buffer to the caller.
45941859428Sblymn */
46041859428Sblymn char *
field_buffer(FIELD * field,int buffer)46141859428Sblymn field_buffer(FIELD *field, int buffer)
46241859428Sblymn {
46341859428Sblymn
46419f07fb2Sblymn char *reformat, *p;
46519f07fb2Sblymn _FORMI_FIELD_LINES *linep;
466cdffa8c1Schristos size_t bufsize, pos;
46719f07fb2Sblymn
46841859428Sblymn if (field == NULL)
46941859428Sblymn return NULL;
47041859428Sblymn
47141859428Sblymn if (buffer >= field->nbuf)
47241859428Sblymn return NULL;
47341859428Sblymn
47419f07fb2Sblymn /*
47519f07fb2Sblymn * We force a sync from the line structs to the buffer here.
47619f07fb2Sblymn * Traditional libform say we don't need to because it is
47719f07fb2Sblymn * done on a REQ_VALIDATE but NetBSD libform previously did
47819f07fb2Sblymn * not enforce this because the buffer contents were always
47919f07fb2Sblymn * current. Changes to line handling make this no longer so
48019f07fb2Sblymn * - the line structs may contain different data to the
48119f07fb2Sblymn * buffer if unsynced.
48219f07fb2Sblymn */
48319f07fb2Sblymn if (_formi_sync_buffer(field) != E_OK)
48419f07fb2Sblymn return NULL;
48519f07fb2Sblymn
486cdffa8c1Schristos if ((field->opts & O_REFORMAT) != O_REFORMAT)
48741859428Sblymn return field->buffers[buffer].string;
488cdffa8c1Schristos
489cdffa8c1Schristos if (field->row_count <= 1)
490cdffa8c1Schristos return strdup(field->buffers[buffer].string);
49119f07fb2Sblymn
4920eefb0f7Sblymn /*
493cdffa8c1Schristos * create a single string containing each line,
494cdffa8c1Schristos * separated by newline, last line having no
495cdffa8c1Schristos * newline, but NUL terminated.
4960eefb0f7Sblymn */
497cdffa8c1Schristos bufsize = pos = 0;
498cdffa8c1Schristos reformat = NULL;
4990eefb0f7Sblymn for (linep = field->alines; linep; linep = linep->next) {
500cdffa8c1Schristos size_t len = strlen(linep->string);
501cdffa8c1Schristos if (len + 1 >= bufsize - pos) {
502cdffa8c1Schristos bufsize += MAX(1024, 2 * len);
503cdffa8c1Schristos p = realloc(reformat, bufsize);
504cdffa8c1Schristos if (p == NULL) {
505cdffa8c1Schristos free(reformat);
506cdffa8c1Schristos return NULL;
50719f07fb2Sblymn }
508cdffa8c1Schristos reformat = p;
509cdffa8c1Schristos }
510cdffa8c1Schristos memcpy(reformat + pos, linep->string, len);
511cdffa8c1Schristos pos += len;
512cdffa8c1Schristos reformat[pos++] = linep->next ? '\n' : '\0';
513cdffa8c1Schristos }
51419f07fb2Sblymn return reformat;
51541859428Sblymn }
51641859428Sblymn
51741859428Sblymn /*
51841859428Sblymn * Set the buffer 0 field status.
51941859428Sblymn */
52041859428Sblymn int
set_field_status(FIELD * field,int status)52141859428Sblymn set_field_status(FIELD *field, int status)
52241859428Sblymn {
52341859428Sblymn
52441859428Sblymn if (field == NULL)
52541859428Sblymn return E_BAD_ARGUMENT;
52641859428Sblymn
52741859428Sblymn if (status != FALSE)
52841859428Sblymn field->buf0_status = TRUE;
52941859428Sblymn else
53041859428Sblymn field->buf0_status = FALSE;
53141859428Sblymn
53241859428Sblymn return E_OK;
53341859428Sblymn }
53441859428Sblymn
53541859428Sblymn /*
53641859428Sblymn * Return the buffer 0 status flag for the given field.
53741859428Sblymn */
53841859428Sblymn int
field_status(FIELD * field)53941859428Sblymn field_status(FIELD *field)
54041859428Sblymn {
54141859428Sblymn
54241859428Sblymn if (field == NULL) /* the default buffer 0 never changes :-) */
54341859428Sblymn return FALSE;
54441859428Sblymn
54541859428Sblymn return field->buf0_status;
54641859428Sblymn }
54741859428Sblymn
54841859428Sblymn /*
54941859428Sblymn * Set the maximum growth for a dynamic field.
55041859428Sblymn */
55141859428Sblymn int
set_max_field(FIELD * fptr,int max)55241859428Sblymn set_max_field(FIELD *fptr, int max)
55341859428Sblymn {
5542a68310bSblymn FIELD *field = (fptr == NULL)? &_formi_default_field : fptr;
55541859428Sblymn
55641859428Sblymn if ((field->opts & O_STATIC) == O_STATIC) /* check if field dynamic */
55741859428Sblymn return E_BAD_ARGUMENT;
55841859428Sblymn
55941859428Sblymn if (max < 0) /* negative numbers are bad.... */
56041859428Sblymn return E_BAD_ARGUMENT;
56141859428Sblymn
56241859428Sblymn field->max = max;
56341859428Sblymn return E_OK;
56441859428Sblymn }
56541859428Sblymn
56641859428Sblymn /*
56741859428Sblymn * Set the field foreground character attributes.
56841859428Sblymn */
56941859428Sblymn int
set_field_fore(FIELD * fptr,chtype attribute)57041859428Sblymn set_field_fore(FIELD *fptr, chtype attribute)
57141859428Sblymn {
57241859428Sblymn FIELD *field = (fptr == NULL)? &_formi_default_field : fptr;
57341859428Sblymn
57441859428Sblymn field->fore = attribute;
57541859428Sblymn return E_OK;
57641859428Sblymn }
57741859428Sblymn
57841859428Sblymn /*
57941859428Sblymn * Return the foreground character attribute for the given field.
58041859428Sblymn */
58141859428Sblymn chtype
field_fore(FIELD * field)58241859428Sblymn field_fore(FIELD *field)
58341859428Sblymn {
58441859428Sblymn if (field == NULL)
58541859428Sblymn return _formi_default_field.fore;
58641859428Sblymn else
58741859428Sblymn return field->fore;
58841859428Sblymn }
58941859428Sblymn
59041859428Sblymn /*
59141859428Sblymn * Set the background character attribute for the given field.
59241859428Sblymn */
59341859428Sblymn int
set_field_back(FIELD * field,chtype attribute)59441859428Sblymn set_field_back(FIELD *field, chtype attribute)
59541859428Sblymn {
59641859428Sblymn if (field == NULL)
59741859428Sblymn _formi_default_field.back = attribute;
59841859428Sblymn else
59941859428Sblymn field->back = attribute;
60041859428Sblymn
60141859428Sblymn return E_OK;
60241859428Sblymn }
60341859428Sblymn
60441859428Sblymn /*
605cc66fb4aSblymn * Get the background character attribute for the given field.
606cc66fb4aSblymn */
607cc66fb4aSblymn chtype
field_back(FIELD * field)608cc66fb4aSblymn field_back(FIELD *field)
609cc66fb4aSblymn {
610cc66fb4aSblymn if (field == NULL)
611cc66fb4aSblymn return _formi_default_field.back;
612cc66fb4aSblymn else
613cc66fb4aSblymn return field->back;
614cc66fb4aSblymn }
615cc66fb4aSblymn
616cc66fb4aSblymn /*
61741859428Sblymn * Set the pad character for the given field.
61841859428Sblymn */
61941859428Sblymn int
set_field_pad(FIELD * field,int pad)62041859428Sblymn set_field_pad(FIELD *field, int pad)
62141859428Sblymn {
62241859428Sblymn if (field == NULL)
62341859428Sblymn _formi_default_field.pad = pad;
62441859428Sblymn else
62541859428Sblymn field->pad = pad;
62641859428Sblymn
62741859428Sblymn return E_OK;
62841859428Sblymn }
62941859428Sblymn
63041859428Sblymn /*
63141859428Sblymn * Return the padding character for the given field.
63241859428Sblymn */
63341859428Sblymn int
field_pad(FIELD * field)63441859428Sblymn field_pad(FIELD *field)
63541859428Sblymn {
63641859428Sblymn if (field == NULL)
63741859428Sblymn return _formi_default_field.pad;
63841859428Sblymn else
63941859428Sblymn return field->pad;
64041859428Sblymn }
64141859428Sblymn
64241859428Sblymn /*
64341859428Sblymn * Set the field initialisation function hook.
64441859428Sblymn */
64541859428Sblymn int
set_field_init(FORM * form,Form_Hook function)64641859428Sblymn set_field_init(FORM *form, Form_Hook function)
64741859428Sblymn {
64841859428Sblymn if (form == NULL)
64941859428Sblymn _formi_default_form.field_init = function;
65041859428Sblymn else
65141859428Sblymn form->field_init = function;
65241859428Sblymn
65341859428Sblymn return E_OK;
65441859428Sblymn }
65541859428Sblymn
65641859428Sblymn /*
65741859428Sblymn * Return the function hook for the field initialisation.
65841859428Sblymn */
65941859428Sblymn Form_Hook
field_init(FORM * form)66041859428Sblymn field_init(FORM *form)
66141859428Sblymn {
66241859428Sblymn if (form == NULL)
66341859428Sblymn return _formi_default_form.field_init;
66441859428Sblymn else
66541859428Sblymn return form->field_init;
66641859428Sblymn }
66741859428Sblymn
66841859428Sblymn /*
66941859428Sblymn * Set the field termination function hook.
67041859428Sblymn */
67141859428Sblymn int
set_field_term(FORM * form,Form_Hook function)67241859428Sblymn set_field_term(FORM *form, Form_Hook function)
67341859428Sblymn {
67441859428Sblymn if (form == NULL)
67541859428Sblymn _formi_default_form.field_term = function;
67641859428Sblymn else
67741859428Sblymn form->field_term = function;
67841859428Sblymn
67941859428Sblymn return E_OK;
68041859428Sblymn }
68141859428Sblymn
68241859428Sblymn /*
68341859428Sblymn * Return the function hook defined for the field termination.
68441859428Sblymn */
68541859428Sblymn Form_Hook
field_term(FORM * form)68641859428Sblymn field_term(FORM *form)
68741859428Sblymn {
68841859428Sblymn if (form == NULL)
68941859428Sblymn return _formi_default_form.field_term;
69041859428Sblymn else
69141859428Sblymn return form->field_term;
69241859428Sblymn }
69341859428Sblymn
69441859428Sblymn /*
69541859428Sblymn * Set the page flag on the given field to indicate it is the start of a
69641859428Sblymn * new page.
69741859428Sblymn */
69841859428Sblymn int
set_new_page(FIELD * fptr,int page)69941859428Sblymn set_new_page(FIELD *fptr, int page)
70041859428Sblymn {
70141859428Sblymn FIELD *field = (fptr == NULL)? &_formi_default_field : fptr;
70241859428Sblymn
70341859428Sblymn if (field->parent != NULL) /* check if field is connected to a form */
70441859428Sblymn return E_CONNECTED;
70541859428Sblymn
70641859428Sblymn field->page_break = (page != FALSE);
70741859428Sblymn return E_OK;
70841859428Sblymn }
70941859428Sblymn
71041859428Sblymn /*
71141859428Sblymn * Return the page status for the given field. TRUE is returned if the
71241859428Sblymn * field is the start of a new page.
71341859428Sblymn */
71441859428Sblymn int
new_page(FIELD * field)71541859428Sblymn new_page(FIELD *field)
71641859428Sblymn {
71741859428Sblymn if (field == NULL)
71841859428Sblymn return _formi_default_field.page_break;
71941859428Sblymn else
72041859428Sblymn return field->page_break;
72141859428Sblymn }
72241859428Sblymn
72341859428Sblymn /*
72441859428Sblymn * Return the index of the field in the form fields array.
72541859428Sblymn */
72641859428Sblymn int
field_index(FIELD * field)72741859428Sblymn field_index(FIELD *field)
72841859428Sblymn {
72941859428Sblymn if (field == NULL)
730cc66fb4aSblymn return E_BAD_ARGUMENT;
73141859428Sblymn
73241859428Sblymn if (field->parent == NULL)
733cc66fb4aSblymn return E_NOT_CONNECTED;
73441859428Sblymn
73541859428Sblymn return field->index;
73641859428Sblymn }
73741859428Sblymn
73841859428Sblymn /*
73941859428Sblymn * Internal function that does most of the work to create a new field.
74041859428Sblymn * The new field is initialised from the information in the prototype
74141859428Sblymn * field passed.
74241859428Sblymn * Returns NULL on error.
74341859428Sblymn */
74441859428Sblymn static FIELD *
_formi_create_field(FIELD * prototype,int rows,int cols,int frow,int fcol,int nrows,int nbuf)74541859428Sblymn _formi_create_field(FIELD *prototype, int rows, int cols, int frow,
74641859428Sblymn int fcol, int nrows, int nbuf)
74741859428Sblymn {
74841859428Sblymn FIELD *new;
74941859428Sblymn
75041859428Sblymn if ((rows <= 0) || (cols <= 0) || (frow < 0) || (fcol < 0) ||
75141859428Sblymn (nrows < 0) || (nbuf < 0))
75241859428Sblymn return NULL;
75341859428Sblymn
754*0cf98320Schristos if ((new = malloc(sizeof(*new))) == NULL) {
75541859428Sblymn return NULL;
75641859428Sblymn }
75741859428Sblymn
75841859428Sblymn /* copy in the default field info */
759*0cf98320Schristos memcpy(new, prototype, sizeof(*new));
76041859428Sblymn
76141859428Sblymn new->nbuf = nbuf + 1;
76241859428Sblymn new->rows = rows;
76341859428Sblymn new->cols = cols;
76441859428Sblymn new->form_row = frow;
76541859428Sblymn new->form_col = fcol;
76641859428Sblymn new->nrows = nrows;
76741859428Sblymn new->link = new;
76841859428Sblymn return new;
76941859428Sblymn }
77041859428Sblymn
77141859428Sblymn /*
77241859428Sblymn * Create a new field structure.
77341859428Sblymn */
77441859428Sblymn FIELD *
new_field(int rows,int cols,int frow,int fcol,int nrows,int nbuf)77541859428Sblymn new_field(int rows, int cols, int frow, int fcol, int nrows, int nbuf)
77641859428Sblymn {
77741859428Sblymn FIELD *new;
77841859428Sblymn int i;
77941859428Sblymn
78041859428Sblymn
78141859428Sblymn if ((new = _formi_create_field(&_formi_default_field, rows, cols,
78241859428Sblymn frow, fcol, nrows, nbuf)) == NULL)
78341859428Sblymn return NULL;
78441859428Sblymn
785*0cf98320Schristos if ((new->buffers = calloc(nbuf + 1, sizeof(*new->buffers))) == NULL) {
78641859428Sblymn free(new);
78741859428Sblymn return NULL;
78841859428Sblymn }
78941859428Sblymn
790790e1a7fSblymn /* Initialise the strings to a zero length string */
79141859428Sblymn for (i = 0; i < nbuf + 1; i++) {
792790e1a7fSblymn if ((new->buffers[i].string =
793*0cf98320Schristos malloc(sizeof(*new->buffers[i].string))) == NULL) {
794*0cf98320Schristos goto out;
7957ffbe072Sblymn }
796790e1a7fSblymn new->buffers[i].string[0] = '\0';
79741859428Sblymn new->buffers[i].length = 0;
798790e1a7fSblymn new->buffers[i].allocated = 1;
79941859428Sblymn }
80041859428Sblymn
801*0cf98320Schristos if ((new->alines = malloc(sizeof(*new->alines))) == NULL) {
802*0cf98320Schristos goto out;
8037ffbe072Sblymn }
8047ffbe072Sblymn
80598eb8895Sroy new->alines->prev = NULL;
80698eb8895Sroy new->alines->next = NULL;
80798eb8895Sroy new->alines->allocated = 0;
80898eb8895Sroy new->alines->length = 0;
80998eb8895Sroy new->alines->expanded = 0;
81098eb8895Sroy new->alines->string = NULL;
81198eb8895Sroy new->alines->hard_ret = FALSE;
81298eb8895Sroy new->alines->tabs = NULL;
81398eb8895Sroy new->start_line = new->alines;
81498eb8895Sroy new->cur_line = new->alines;
8157ffbe072Sblymn
81641859428Sblymn return new;
817*0cf98320Schristos out:
818*0cf98320Schristos while (--i >= 0) {
819*0cf98320Schristos free(new->buffers[i].string);
820*0cf98320Schristos }
821*0cf98320Schristos free(new->buffers);
822*0cf98320Schristos free(new);
823*0cf98320Schristos return NULL;
82441859428Sblymn }
82541859428Sblymn
82641859428Sblymn /*
827f0a7346dSsnj * Duplicate the given field, including its buffers.
82841859428Sblymn */
82941859428Sblymn FIELD *
dup_field(FIELD * field,int frow,int fcol)83041859428Sblymn dup_field(FIELD *field, int frow, int fcol)
83141859428Sblymn {
83241859428Sblymn FIELD *new;
83341859428Sblymn size_t row_len, buf_len;
83441859428Sblymn
83541859428Sblymn if (field == NULL)
83641859428Sblymn return NULL;
83741859428Sblymn
838*0cf98320Schristos /* XXX: this right???? */
83941859428Sblymn if ((new = _formi_create_field(field, (int) field->rows,
84041859428Sblymn (int) field->cols,
84141859428Sblymn frow, fcol, (int) field->nrows,
84241859428Sblymn field->nbuf - 1)) == NULL)
84341859428Sblymn return NULL;
84441859428Sblymn
84541859428Sblymn row_len = (field->rows + field->nrows + 1) * field->cols;
846*0cf98320Schristos buf_len = (field->nbuf + 1) * row_len * sizeof(*new->buffers);
84741859428Sblymn
848*0cf98320Schristos /* XXX: dups buffers but not their strings? */
849*0cf98320Schristos if ((new->buffers = malloc(buf_len)) == NULL) {
85041859428Sblymn free(new);
85141859428Sblymn return NULL;
85241859428Sblymn }
85341859428Sblymn
85441859428Sblymn /* copy the buffers from the source field into the new copy */
855*0cf98320Schristos memcpy(new->buffers, field->buffers, buf_len);
85641859428Sblymn
85741859428Sblymn return new;
85841859428Sblymn }
85941859428Sblymn
86041859428Sblymn /*
86141859428Sblymn * Create a new field at the specified location by duplicating the given
86241859428Sblymn * field. The buffers are shared with the parent field.
86341859428Sblymn */
86441859428Sblymn FIELD *
link_field(FIELD * field,int frow,int fcol)86541859428Sblymn link_field(FIELD *field, int frow, int fcol)
86641859428Sblymn {
86741859428Sblymn FIELD *new;
86841859428Sblymn
86941859428Sblymn if (field == NULL)
87041859428Sblymn return NULL;
87141859428Sblymn
87241859428Sblymn if ((new = _formi_create_field(field, (int) field->rows,
87341859428Sblymn (int) field->cols,
87441859428Sblymn frow, fcol, (int) field->nrows,
87541859428Sblymn field->nbuf - 1)) == NULL)
87641859428Sblymn return NULL;
87741859428Sblymn
87841859428Sblymn new->link = field->link;
87941859428Sblymn field->link = new;
88041859428Sblymn
88141859428Sblymn /* we are done. The buffer pointer was copied during the field
88241859428Sblymn creation. */
88341859428Sblymn return new;
88441859428Sblymn }
88541859428Sblymn
88641859428Sblymn /*
88741859428Sblymn * Release all storage allocated to the field
88841859428Sblymn */
88941859428Sblymn int
free_field(FIELD * field)89041859428Sblymn free_field(FIELD *field)
89141859428Sblymn {
89241859428Sblymn FIELD *flink;
89369a50ce4Sjoerg unsigned int i;
894759e545dSblymn _formi_tab_t *ts, *nts;
89541859428Sblymn
89641859428Sblymn if (field == NULL)
89741859428Sblymn return E_BAD_ARGUMENT;
89841859428Sblymn
89941859428Sblymn if (field->parent != NULL)
90041859428Sblymn return E_CONNECTED;
90141859428Sblymn
90241859428Sblymn if (field->link == field) { /* check if field linked */
90341859428Sblymn /* no it is not - release the buffers */
90441859428Sblymn free(field->buffers);
905759e545dSblymn /* free the tab structures */
90669a50ce4Sjoerg for (i = 0; i + 1 < field->row_count; i++) {
90798eb8895Sroy if (field->alines[i].tabs != NULL) {
90898eb8895Sroy ts = field->alines[i].tabs;
909759e545dSblymn while (ts != NULL) {
910759e545dSblymn nts = ts->fwd;
911759e545dSblymn free(ts);
912759e545dSblymn ts = nts;
913759e545dSblymn }
914759e545dSblymn }
915759e545dSblymn }
91641859428Sblymn } else {
91741859428Sblymn /* is linked, traverse the links to find the field referring
91841859428Sblymn * to the one to be freed.
91941859428Sblymn */
92041859428Sblymn for (flink = field->link; flink != field; flink = flink->link);
92141859428Sblymn flink->link = field->link;
92241859428Sblymn }
92341859428Sblymn
92441859428Sblymn free(field);
92541859428Sblymn return E_OK;
92641859428Sblymn }
92741859428Sblymn
92841859428Sblymn
929