Home | History | Annotate | Line # | Download | only in libform
field.c revision 1.25.12.1
      1  1.25.12.1    tls /*	$NetBSD: field.c,v 1.25.12.1 2014/08/20 00:02:17 tls Exp $	*/
      2        1.1  blymn /*-
      3        1.1  blymn  * Copyright (c) 1998-1999 Brett Lymn
      4        1.1  blymn  *                         (blymn (at) baea.com.au, brett_lymn (at) yahoo.com.au)
      5        1.1  blymn  * All rights reserved.
      6        1.1  blymn  *
      7        1.1  blymn  * This code has been donated to The NetBSD Foundation by the Author.
      8        1.1  blymn  *
      9        1.1  blymn  * Redistribution and use in source and binary forms, with or without
     10        1.1  blymn  * modification, are permitted provided that the following conditions
     11        1.1  blymn  * are met:
     12        1.1  blymn  * 1. Redistributions of source code must retain the above copyright
     13        1.1  blymn  *    notice, this list of conditions and the following disclaimer.
     14        1.1  blymn  * 2. The name of the author may not be used to endorse or promote products
     15       1.12    wiz  *    derived from this software without specific prior written permission
     16        1.1  blymn  *
     17        1.1  blymn  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
     18        1.1  blymn  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     19        1.1  blymn  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
     20        1.1  blymn  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
     21        1.1  blymn  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
     22        1.1  blymn  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     23        1.1  blymn  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     24        1.1  blymn  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     25        1.1  blymn  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
     26        1.1  blymn  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     27        1.1  blymn  *
     28        1.1  blymn  *
     29        1.1  blymn  */
     30       1.22  lukem 
     31       1.22  lukem #include <sys/cdefs.h>
     32  1.25.12.1    tls __RCSID("$NetBSD: field.c,v 1.25.12.1 2014/08/20 00:02:17 tls Exp $");
     33        1.1  blymn 
     34  1.25.12.1    tls #include <sys/param.h>
     35        1.1  blymn #include <stdlib.h>
     36        1.1  blymn #include <strings.h>
     37       1.21  blymn #include <stdarg.h>
     38        1.1  blymn #include <form.h>
     39        1.1  blymn #include "internals.h"
     40        1.1  blymn 
     41        1.1  blymn extern FORM _formi_default_form;
     42        1.1  blymn 
     43        1.1  blymn FIELD _formi_default_field = {
     44        1.1  blymn 	0, /* rows in the field */
     45        1.1  blymn 	0, /* columns in the field */
     46        1.1  blymn 	0, /* dynamic rows */
     47        1.1  blymn 	0, /* dynamic columns */
     48        1.1  blymn 	0, /* maximum growth */
     49        1.1  blymn 	0, /* starting row in the form subwindow */
     50        1.1  blymn 	0, /* starting column in the form subwindow */
     51        1.1  blymn 	0, /* number of off screen rows */
     52        1.1  blymn 	0, /* index of this field in form fields array. */
     53        1.1  blymn 	0, /* number of buffers associated with this field */
     54        1.1  blymn 	FALSE, /* set to true if buffer 0 has changed. */
     55        1.1  blymn 	NO_JUSTIFICATION, /* justification style of the field */
     56        1.1  blymn 	FALSE, /* set to true if field is in overlay mode */
     57       1.23  blymn 	NULL, /* pointer to the current line cursor is on */
     58        1.1  blymn 	0, /* starting char in string (horiz scroll) */
     59       1.23  blymn 	NULL, /* starting line in field (vert scroll) */
     60        1.1  blymn 	0, /* number of rows actually used in field */
     61       1.15  blymn 	0, /* actual pos of cursor in row, not same as x pos due to tabs */
     62        1.1  blymn 	0, /* x pos of cursor in field */
     63        1.1  blymn 	0, /* y pos of cursor in field */
     64        1.1  blymn 	0, /* start of a new page on the form if 1 */
     65        1.1  blymn 	0, /* number of the page this field is on */
     66        1.1  blymn 	A_NORMAL, /* character attributes for the foreground */
     67        1.3  blymn 	A_NORMAL, /* character attributes for the background */
     68        1.1  blymn 	' ', /* padding character */
     69        1.1  blymn 	DEFAULT_FORM_OPTS, /* options for the field */
     70        1.1  blymn 	NULL, /* the form this field is bound to, if any */
     71        1.1  blymn 	NULL, /* field above this one */
     72        1.1  blymn 	NULL, /* field below this one */
     73        1.1  blymn 	NULL, /* field to the left of this one */
     74        1.1  blymn 	NULL, /* field to the right of this one */
     75        1.1  blymn 	NULL,  /* user defined pointer. */
     76        1.1  blymn 	NULL, /* used if fields are linked */
     77        1.1  blymn 	NULL, /* type struct for the field */
     78        1.1  blymn 	{NULL, NULL}, /* circle queue glue for sorting fields */
     79        1.1  blymn 	NULL, /* args for field type. */
     80       1.10  blymn 	NULL, /* pointer to the array of lines structures. */
     81       1.23  blymn 	NULL, /* list of lines available for reuse */
     82        1.1  blymn 	NULL, /* array of buffers for the field */
     83        1.1  blymn };
     84        1.1  blymn 
     85        1.1  blymn /* internal function prototypes */
     86       1.21  blymn static int
     87       1.23  blymn field_buffer_init(FIELD *field, int buffer, unsigned int len);
     88        1.1  blymn static FIELD *
     89        1.1  blymn _formi_create_field(FIELD *, int, int, int, int, int, int);
     90        1.1  blymn 
     91        1.1  blymn 
     92        1.1  blymn /*
     93        1.1  blymn  * Set the userptr for the field
     94        1.1  blymn  */
     95        1.1  blymn int
     96        1.2  blymn set_field_userptr(FIELD *field, void *ptr)
     97        1.1  blymn {
     98        1.1  blymn 	FIELD *fp = (field == NULL) ? &_formi_default_field : field;
     99        1.1  blymn 
    100        1.1  blymn 	fp->userptr = ptr;
    101        1.1  blymn 
    102        1.1  blymn 	return E_OK;
    103        1.1  blymn }
    104        1.1  blymn 
    105        1.1  blymn /*
    106        1.1  blymn  * Return the userptr for the field.
    107        1.1  blymn  */
    108        1.1  blymn 
    109        1.2  blymn void *
    110        1.1  blymn field_userptr(FIELD *field)
    111        1.1  blymn {
    112        1.1  blymn 	if (field == NULL)
    113        1.1  blymn 		return _formi_default_field.userptr;
    114        1.1  blymn 	else
    115        1.1  blymn 		return field->userptr;
    116        1.1  blymn }
    117        1.1  blymn 
    118        1.1  blymn /*
    119        1.1  blymn  * Set the options for the designated field.
    120        1.1  blymn  */
    121        1.1  blymn int
    122        1.1  blymn set_field_opts(FIELD *field, Form_Options options)
    123        1.1  blymn {
    124        1.8  blymn 	int i;
    125        1.8  blymn 
    126        1.1  blymn 	FIELD *fp = (field == NULL) ? &_formi_default_field : field;
    127        1.1  blymn 
    128        1.8  blymn 	  /* not allowed to set opts if the field is the current one */
    129        1.8  blymn 	if ((field != NULL) && (field->parent != NULL) &&
    130        1.8  blymn 	    (field->parent->cur_field == field->index))
    131        1.8  blymn 		return E_CURRENT;
    132        1.8  blymn 
    133        1.8  blymn 	if ((options & O_STATIC) == O_STATIC) {
    134       1.20  blymn 		for (i = 0; i < fp->nbuf; i++) {
    135       1.20  blymn 			if (fp->buffers[i].length > fp->cols)
    136       1.20  blymn 				fp->buffers[i].string[fp->cols] = '\0';
    137        1.8  blymn 		}
    138        1.8  blymn 	}
    139        1.8  blymn 
    140        1.1  blymn 	fp->opts = options;
    141        1.1  blymn 
    142       1.19  blymn 	  /* if appropriate, redraw the field */
    143       1.19  blymn 	if ((field != NULL) && (field->parent != NULL)
    144       1.19  blymn 	    && (field->parent->posted == 1)) {
    145       1.19  blymn 		_formi_redraw_field(field->parent, field->index);
    146       1.19  blymn 		pos_form_cursor(field->parent);
    147       1.19  blymn 		wrefresh(field->parent->scrwin);
    148       1.19  blymn 	}
    149       1.19  blymn 
    150        1.1  blymn 	return E_OK;
    151        1.1  blymn }
    152        1.1  blymn 
    153        1.1  blymn /*
    154        1.1  blymn  * Turn on the passed field options.
    155        1.1  blymn  */
    156        1.1  blymn int
    157        1.1  blymn field_opts_on(FIELD *field, Form_Options options)
    158        1.1  blymn {
    159        1.8  blymn 	int i;
    160        1.8  blymn 
    161        1.1  blymn 	FIELD *fp = (field == NULL) ? &_formi_default_field : field;
    162        1.1  blymn 
    163        1.8  blymn 	  /* not allowed to set opts if the field is the current one */
    164        1.8  blymn 	if ((field != NULL) && (field->parent != NULL) &&
    165        1.8  blymn 	    (field->parent->cur_field == field->index))
    166        1.8  blymn 		return E_CURRENT;
    167        1.8  blymn 
    168        1.8  blymn 	if ((options & O_STATIC) == O_STATIC) {
    169       1.20  blymn 		for (i = 0; i < fp->nbuf; i++) {
    170       1.20  blymn 			if (fp->buffers[i].length > fp->cols)
    171       1.20  blymn 				fp->buffers[i].string[fp->cols] = '\0';
    172        1.8  blymn 		}
    173        1.8  blymn 	}
    174        1.8  blymn 
    175        1.1  blymn 	fp->opts |= options;
    176       1.19  blymn 
    177       1.19  blymn 	  /* if appropriate, redraw the field */
    178       1.19  blymn 	if ((field != NULL) && (field->parent != NULL)
    179       1.19  blymn 	    && (field->parent->posted == 1)) {
    180       1.19  blymn 		_formi_redraw_field(field->parent, field->index);
    181       1.19  blymn 		pos_form_cursor(field->parent);
    182       1.19  blymn 		wrefresh(field->parent->scrwin);
    183       1.19  blymn 	}
    184        1.1  blymn 
    185        1.1  blymn 	return E_OK;
    186        1.1  blymn }
    187        1.1  blymn 
    188        1.1  blymn /*
    189        1.1  blymn  * Turn off the passed field options.
    190        1.1  blymn  */
    191        1.1  blymn int
    192        1.1  blymn field_opts_off(FIELD *field, Form_Options options)
    193        1.1  blymn {
    194        1.1  blymn 	FIELD *fp = (field == NULL) ? &_formi_default_field : field;
    195        1.1  blymn 
    196        1.8  blymn 	  /* not allowed to set opts if the field is the current one */
    197        1.8  blymn 	if ((field != NULL) && (field->parent != NULL) &&
    198        1.8  blymn 	    (field->parent->cur_field == field->index))
    199        1.8  blymn 		return E_CURRENT;
    200        1.8  blymn 
    201        1.1  blymn 	fp->opts &= ~options;
    202       1.19  blymn 
    203       1.19  blymn 	  /* if appropriate, redraw the field */
    204       1.19  blymn 	if ((field != NULL) && (field->parent != NULL)
    205       1.19  blymn 	    && (field->parent->posted == 1)) {
    206       1.19  blymn 		_formi_redraw_field(field->parent, field->index);
    207       1.19  blymn 		pos_form_cursor(field->parent);
    208       1.19  blymn 		wrefresh(field->parent->scrwin);
    209       1.19  blymn 	}
    210       1.19  blymn 
    211        1.1  blymn 	return E_OK;
    212        1.1  blymn }
    213        1.1  blymn 
    214        1.1  blymn /*
    215        1.1  blymn  * Return the field options associated with the passed field.
    216        1.1  blymn  */
    217        1.1  blymn Form_Options
    218        1.1  blymn field_opts(FIELD *field)
    219        1.1  blymn {
    220        1.1  blymn 	if (field == NULL)
    221        1.1  blymn 		return _formi_default_field.opts;
    222        1.1  blymn 	else
    223        1.1  blymn 		return field->opts;
    224        1.1  blymn }
    225        1.1  blymn 
    226        1.1  blymn /*
    227        1.1  blymn  * Set the justification for the passed field.
    228        1.1  blymn  */
    229        1.1  blymn int
    230        1.1  blymn set_field_just(FIELD *field, int justification)
    231        1.1  blymn {
    232        1.1  blymn 	FIELD *fp = (field == NULL) ? &_formi_default_field : field;
    233        1.1  blymn 
    234        1.8  blymn 	  /*
    235        1.8  blymn 	   * not allowed to set justification if the field is
    236        1.8  blymn 	   * the current one
    237        1.8  blymn 	   */
    238        1.8  blymn 	if ((field != NULL) && (field->parent != NULL) &&
    239        1.8  blymn 	    (field->parent->cur_field == field->index))
    240        1.8  blymn 		return E_CURRENT;
    241        1.8  blymn 
    242        1.1  blymn 	if ((justification < MIN_JUST_STYLE) /* check justification valid */
    243        1.1  blymn 	    || (justification > MAX_JUST_STYLE))
    244        1.1  blymn 		return E_BAD_ARGUMENT;
    245       1.17  blymn 
    246       1.17  blymn 	  /* only allow justification on static, single row fields */
    247       1.17  blymn 	if (((fp->opts & O_STATIC) != O_STATIC) ||
    248       1.17  blymn 	    ((fp->rows + fp->nrows) > 1))
    249       1.17  blymn 		return E_BAD_ARGUMENT;
    250        1.1  blymn 
    251        1.1  blymn 	fp->justification = justification;
    252       1.17  blymn 
    253       1.17  blymn 	_formi_init_field_xpos(fp);
    254       1.17  blymn 
    255        1.1  blymn 	return E_OK;
    256        1.1  blymn }
    257        1.1  blymn 
    258        1.1  blymn /*
    259        1.1  blymn  * Return the justification style of the field passed.
    260        1.1  blymn  */
    261        1.1  blymn int
    262        1.1  blymn field_just(FIELD *field)
    263        1.1  blymn {
    264        1.1  blymn 	if (field == NULL)
    265        1.1  blymn 		return _formi_default_field.justification;
    266        1.1  blymn 	else
    267        1.1  blymn 		return field->justification;
    268        1.1  blymn }
    269        1.1  blymn 
    270        1.1  blymn /*
    271        1.1  blymn  * Return information about the field passed.
    272        1.1  blymn  */
    273        1.1  blymn int
    274        1.1  blymn field_info(FIELD *field, int *rows, int *cols, int *frow, int *fcol,
    275        1.1  blymn 	   int *nrow, int *nbuf)
    276        1.1  blymn {
    277        1.1  blymn 	if (field == NULL)
    278        1.1  blymn 		return E_BAD_ARGUMENT;
    279        1.1  blymn 
    280        1.1  blymn 	*rows = field->rows;
    281        1.1  blymn 	*cols = field->cols;
    282        1.1  blymn 	*frow = field->form_row;
    283        1.1  blymn 	*fcol = field->form_col;
    284        1.1  blymn 	*nrow = field->nrows;
    285        1.1  blymn 	*nbuf = field->nbuf;
    286        1.1  blymn 
    287        1.1  blymn 	return E_OK;
    288        1.1  blymn }
    289        1.1  blymn 
    290        1.1  blymn /*
    291        1.1  blymn  * Report the dynamic field information.
    292        1.1  blymn  */
    293        1.1  blymn int
    294        1.1  blymn dynamic_field_info(FIELD *field, int *drows, int *dcols, int *max)
    295        1.1  blymn {
    296        1.1  blymn 	if (field == NULL)
    297        1.1  blymn 		return E_BAD_ARGUMENT;
    298        1.1  blymn 
    299        1.8  blymn 	if ((field->opts & O_STATIC) == O_STATIC) {
    300        1.8  blymn 		*drows = field->rows;
    301        1.8  blymn 		*dcols = field->cols;
    302        1.8  blymn 	} else {
    303        1.8  blymn 		*drows = field->drows;
    304        1.8  blymn 		*dcols = field->dcols;
    305        1.8  blymn 	}
    306        1.8  blymn 
    307        1.1  blymn 	*max = field->max;
    308        1.1  blymn 
    309        1.1  blymn 	return E_OK;
    310        1.1  blymn }
    311        1.1  blymn 
    312        1.1  blymn /*
    313       1.21  blymn  * Init all the field variables, perform wrapping and other tasks
    314       1.21  blymn  * after the field buffer is set.
    315       1.21  blymn  */
    316       1.21  blymn static int
    317       1.23  blymn field_buffer_init(FIELD *field, int buffer, unsigned int len)
    318       1.21  blymn {
    319       1.21  blymn 	int status;
    320       1.23  blymn 	char *newp;
    321       1.21  blymn 
    322       1.21  blymn 	if (buffer == 0) {
    323       1.21  blymn 		field->start_char = 0;
    324       1.21  blymn 		field->start_line = 0;
    325       1.21  blymn 		field->row_xpos = 0;
    326       1.21  blymn 		field->cursor_xpos = 0;
    327       1.21  blymn 		field->cursor_ypos = 0;
    328       1.23  blymn 		field->row_count = 1; /* must be at least one row  XXX need to shift old rows (if any) to free list??? */
    329       1.25    roy 		field->alines->length = len;
    330       1.25    roy 		if ((newp = realloc(field->alines->string,
    331       1.24    wiz 				    (size_t) len + 1)) == NULL)
    332       1.23  blymn 			return E_SYSTEM_ERROR;
    333       1.25    roy 		field->alines->string = newp;
    334       1.25    roy 		field->alines->allocated = len + 1;
    335       1.25    roy 		strlcpy(field->alines->string, field->buffers[buffer].string,
    336       1.24    wiz 			(size_t) len + 1);
    337       1.25    roy 		field->alines->expanded =
    338       1.25    roy 			_formi_tab_expanded_length(field->alines->string,
    339       1.25    roy 						   0, field->alines->length);
    340       1.23  blymn 
    341       1.25    roy 		field->start_line = field->alines;
    342       1.25    roy 		field->cur_line = field->alines;
    343       1.23  blymn 
    344       1.21  blymn 		  /* we have to hope the wrap works - if it does not then the
    345       1.21  blymn 		     buffer is pretty much borked */
    346       1.23  blymn 		status = _formi_wrap_field(field, field->cur_line);
    347       1.21  blymn 		if (status != E_OK)
    348       1.21  blymn 			return status;
    349       1.21  blymn 
    350       1.21  blymn 		  /*
    351       1.21  blymn 		   * calculate the tabs for a single row field, the
    352       1.21  blymn 		   * multiline case is handled when the wrap is done.
    353       1.21  blymn 		   */
    354       1.21  blymn 		if (field->row_count == 1)
    355       1.25    roy 			_formi_calculate_tabs(field->alines);
    356       1.21  blymn 
    357       1.21  blymn 		  /* redraw the field to reflect the new contents. If the field
    358       1.21  blymn 		   * is attached....
    359       1.21  blymn 		   */
    360       1.21  blymn 		if ((field->parent != NULL) && (field->parent->posted == 1)) {
    361       1.21  blymn 			_formi_redraw_field(field->parent, field->index);
    362       1.21  blymn 			  /* make sure cursor goes back to current field */
    363       1.21  blymn 			pos_form_cursor(field->parent);
    364       1.21  blymn 		}
    365       1.21  blymn 	}
    366       1.21  blymn 
    367       1.21  blymn 	return E_OK;
    368       1.21  blymn }
    369       1.21  blymn 
    370       1.21  blymn 
    371       1.21  blymn /*
    372       1.21  blymn  * Set the field buffer to the string that results from processing
    373       1.21  blymn  * the given format (fmt) using sprintf.
    374       1.21  blymn  */
    375       1.21  blymn int
    376       1.21  blymn set_field_printf(FIELD *field, int buffer, char *fmt, ...)
    377       1.21  blymn {
    378       1.21  blymn 	int len;
    379       1.21  blymn 	va_list args;
    380       1.21  blymn 
    381       1.21  blymn 	if (field == NULL)
    382       1.21  blymn 		return E_BAD_ARGUMENT;
    383       1.21  blymn 
    384       1.21  blymn 	if (buffer >= field->nbuf)
    385       1.21  blymn 		return E_BAD_ARGUMENT;
    386       1.21  blymn 
    387       1.21  blymn 	va_start(args, fmt);
    388       1.21  blymn 	  /* check for buffer already existing, free the storage */
    389       1.21  blymn 	if (field->buffers[buffer].allocated != 0)
    390       1.21  blymn 		free(field->buffers[buffer].string);
    391       1.21  blymn 
    392       1.21  blymn 	len = vasprintf(&field->buffers[buffer].string, fmt, args);
    393       1.21  blymn 	va_end(args);
    394       1.21  blymn 	if (len < 0)
    395       1.21  blymn 		return E_SYSTEM_ERROR;
    396       1.21  blymn 
    397       1.21  blymn 	field->buffers[buffer].length = len;
    398       1.21  blymn 	field->buffers[buffer].allocated = len + 1;
    399       1.21  blymn 	if (((field->opts & O_STATIC) == O_STATIC) && (len > field->cols)
    400       1.21  blymn 	    && ((field->rows + field->nrows) == 1))
    401       1.21  blymn 		len = field->cols;
    402       1.21  blymn 
    403       1.21  blymn 	field->buffers[buffer].string[len] = '\0';
    404       1.21  blymn 	return field_buffer_init(field, buffer, (unsigned int) len);
    405       1.21  blymn }
    406       1.21  blymn 
    407       1.21  blymn /*
    408        1.1  blymn  * Set the value of the field buffer to the value given.
    409        1.1  blymn  */
    410        1.1  blymn 
    411        1.1  blymn int
    412        1.1  blymn set_field_buffer(FIELD *field, int buffer, char *value)
    413        1.1  blymn {
    414       1.23  blymn 	unsigned int len;
    415        1.5  blymn 	int status;
    416        1.1  blymn 
    417        1.1  blymn 	if (field == NULL)
    418        1.1  blymn 		return E_BAD_ARGUMENT;
    419        1.1  blymn 
    420        1.1  blymn 	if (buffer >= field->nbuf) /* make sure buffer is valid */
    421        1.1  blymn 		return E_BAD_ARGUMENT;
    422        1.1  blymn 
    423       1.23  blymn 	len = (unsigned int) strlen(value);
    424       1.10  blymn 	if (((field->opts & O_STATIC) == O_STATIC) && (len > field->cols)
    425       1.10  blymn 	    && ((field->rows + field->nrows) == 1))
    426        1.6  blymn 		len = field->cols;
    427       1.11  blymn 
    428       1.11  blymn #ifdef DEBUG
    429       1.11  blymn 	if (_formi_create_dbg_file() != E_OK)
    430       1.11  blymn 		return E_SYSTEM_ERROR;
    431       1.11  blymn 
    432       1.11  blymn 	fprintf(dbg,
    433       1.11  blymn 		"set_field_buffer: entry: len = %d, value = %s, buffer=%d\n",
    434       1.11  blymn 		len, value, buffer);
    435       1.11  blymn 	fprintf(dbg, "set_field_buffer: entry: string = ");
    436       1.11  blymn 	if (field->buffers[buffer].string != NULL)
    437       1.11  blymn 		fprintf(dbg, "%s, len = %d\n", field->buffers[buffer].string,
    438       1.11  blymn 			field->buffers[buffer].length);
    439       1.11  blymn 	else
    440       1.11  blymn 		fprintf(dbg, "(null), len = 0\n");
    441       1.11  blymn 	fprintf(dbg, "set_field_buffer: entry: lines.len = %d\n",
    442       1.25    roy 		field->alines[0].length);
    443       1.11  blymn #endif
    444       1.11  blymn 
    445        1.6  blymn 	if ((field->buffers[buffer].string =
    446       1.23  blymn 	     (char *) realloc(field->buffers[buffer].string,
    447       1.23  blymn 			      (size_t) len + 1)) == NULL)
    448        1.1  blymn 		return E_SYSTEM_ERROR;
    449        1.1  blymn 
    450       1.23  blymn 	strlcpy(field->buffers[buffer].string, value, (size_t) len + 1);
    451        1.1  blymn 	field->buffers[buffer].length = len;
    452        1.1  blymn 	field->buffers[buffer].allocated = len + 1;
    453       1.21  blymn 	status = field_buffer_init(field, buffer, len);
    454       1.11  blymn 
    455       1.11  blymn #ifdef DEBUG
    456       1.11  blymn 	fprintf(dbg, "set_field_buffer: exit: len = %d, value = %s\n",
    457       1.11  blymn 		len, value);
    458       1.11  blymn 	fprintf(dbg, "set_field_buffer: exit: string = %s, len = %d\n",
    459       1.11  blymn 		field->buffers[buffer].string, field->buffers[buffer].length);
    460       1.11  blymn 	fprintf(dbg, "set_field_buffer: exit: lines.len = %d\n",
    461       1.25    roy 		field->alines[0].length);
    462       1.11  blymn #endif
    463        1.1  blymn 
    464       1.21  blymn 	return status;
    465        1.1  blymn }
    466        1.1  blymn 
    467        1.1  blymn /*
    468        1.1  blymn  * Return the requested field buffer to the caller.
    469        1.1  blymn  */
    470        1.1  blymn char *
    471        1.1  blymn field_buffer(FIELD *field, int buffer)
    472        1.1  blymn {
    473        1.1  blymn 
    474       1.23  blymn 	char *reformat, *p;
    475       1.23  blymn 	_FORMI_FIELD_LINES *linep;
    476  1.25.12.1    tls 	size_t bufsize, pos;
    477       1.23  blymn 
    478        1.1  blymn 	if (field == NULL)
    479        1.1  blymn 		return NULL;
    480        1.1  blymn 
    481        1.1  blymn 	if (buffer >= field->nbuf)
    482        1.1  blymn 		return NULL;
    483       1.23  blymn 
    484       1.23  blymn 	  /*
    485       1.23  blymn 	   * We force a sync from the line structs to the buffer here.
    486       1.23  blymn 	   * Traditional libform say we don't need to because it is
    487       1.23  blymn 	   * done on a REQ_VALIDATE but NetBSD libform previously did
    488       1.23  blymn 	   * not enforce this because the buffer contents were always
    489       1.23  blymn 	   * current.  Changes to line handling make this no longer so
    490       1.23  blymn 	   * - the line structs may contain different data to the
    491       1.23  blymn 	   * buffer if unsynced.
    492       1.23  blymn 	   */
    493       1.23  blymn 	if (_formi_sync_buffer(field) != E_OK)
    494       1.23  blymn 		return NULL;
    495        1.1  blymn 
    496  1.25.12.1    tls 	if ((field->opts & O_REFORMAT) != O_REFORMAT)
    497       1.23  blymn 		return field->buffers[buffer].string;
    498       1.23  blymn 
    499  1.25.12.1    tls 	if (field->row_count <= 1)
    500  1.25.12.1    tls 		return strdup(field->buffers[buffer].string);
    501       1.23  blymn 
    502  1.25.12.1    tls 	/*
    503  1.25.12.1    tls 	 * create a single string containing each line,
    504  1.25.12.1    tls 	 * separated by newline, last line having no
    505  1.25.12.1    tls 	 * newline, but NUL terminated.
    506  1.25.12.1    tls 	 */
    507  1.25.12.1    tls 	bufsize = pos = 0;
    508  1.25.12.1    tls 	reformat = NULL;
    509  1.25.12.1    tls 	for (linep = field->alines; linep; linep = linep->next) {
    510  1.25.12.1    tls 		size_t len = strlen(linep->string);
    511  1.25.12.1    tls 		if (len + 1 >= bufsize - pos) {
    512  1.25.12.1    tls 			bufsize += MAX(1024, 2 * len);
    513  1.25.12.1    tls 			p = realloc(reformat, bufsize);
    514  1.25.12.1    tls 			if (p == NULL) {
    515  1.25.12.1    tls 				free(reformat);
    516  1.25.12.1    tls 				return NULL;
    517       1.23  blymn 			}
    518  1.25.12.1    tls 			reformat = p;
    519       1.23  blymn 		}
    520  1.25.12.1    tls 		memcpy(reformat + pos, linep->string, len);
    521  1.25.12.1    tls 		pos += len;
    522  1.25.12.1    tls 		reformat[pos++] = linep->next ? '\n' : '\0';
    523       1.23  blymn 	}
    524  1.25.12.1    tls 	return reformat;
    525        1.1  blymn }
    526        1.1  blymn 
    527        1.1  blymn /*
    528        1.1  blymn  * Set the buffer 0 field status.
    529        1.1  blymn  */
    530        1.1  blymn int
    531        1.1  blymn set_field_status(FIELD *field, int status)
    532        1.1  blymn {
    533        1.1  blymn 
    534        1.1  blymn 	if (field == NULL)
    535        1.1  blymn 		return E_BAD_ARGUMENT;
    536        1.1  blymn 
    537        1.1  blymn 	if (status != FALSE)
    538        1.1  blymn 		field->buf0_status = TRUE;
    539        1.1  blymn 	else
    540        1.1  blymn 		field->buf0_status = FALSE;
    541        1.1  blymn 
    542        1.1  blymn 	return E_OK;
    543        1.1  blymn }
    544        1.1  blymn 
    545        1.1  blymn /*
    546        1.1  blymn  * Return the buffer 0 status flag for the given field.
    547        1.1  blymn  */
    548        1.1  blymn int
    549        1.1  blymn field_status(FIELD *field)
    550        1.1  blymn {
    551        1.1  blymn 
    552        1.1  blymn 	if (field == NULL) /* the default buffer 0 never changes :-) */
    553        1.1  blymn 		return FALSE;
    554        1.1  blymn 
    555        1.1  blymn 	return field->buf0_status;
    556        1.1  blymn }
    557        1.1  blymn 
    558        1.1  blymn /*
    559        1.1  blymn  * Set the maximum growth for a dynamic field.
    560        1.1  blymn  */
    561        1.1  blymn int
    562        1.1  blymn set_max_field(FIELD *fptr, int max)
    563        1.1  blymn {
    564       1.13  blymn 	FIELD *field = (fptr == NULL)? &_formi_default_field : fptr;
    565        1.1  blymn 
    566        1.1  blymn 	if ((field->opts & O_STATIC) == O_STATIC) /* check if field dynamic */
    567        1.1  blymn 		return E_BAD_ARGUMENT;
    568        1.1  blymn 
    569        1.1  blymn 	if (max < 0) /* negative numbers are bad.... */
    570        1.1  blymn 		return E_BAD_ARGUMENT;
    571        1.1  blymn 
    572        1.1  blymn 	field->max = max;
    573        1.1  blymn 	return E_OK;
    574        1.1  blymn }
    575        1.1  blymn 
    576        1.1  blymn /*
    577        1.1  blymn  * Set the field foreground character attributes.
    578        1.1  blymn  */
    579        1.1  blymn int
    580        1.1  blymn set_field_fore(FIELD *fptr, chtype attribute)
    581        1.1  blymn {
    582        1.1  blymn 	FIELD *field = (fptr == NULL)? &_formi_default_field : fptr;
    583        1.1  blymn 
    584        1.1  blymn 	field->fore = attribute;
    585        1.1  blymn 	return E_OK;
    586        1.1  blymn }
    587        1.1  blymn 
    588        1.1  blymn /*
    589        1.1  blymn  * Return the foreground character attribute for the given field.
    590        1.1  blymn  */
    591        1.1  blymn chtype
    592        1.1  blymn field_fore(FIELD *field)
    593        1.1  blymn {
    594        1.1  blymn 	if (field == NULL)
    595        1.1  blymn 		return _formi_default_field.fore;
    596        1.1  blymn 	else
    597        1.1  blymn 		return field->fore;
    598        1.1  blymn }
    599        1.1  blymn 
    600        1.1  blymn /*
    601        1.1  blymn  * Set the background character attribute for the given field.
    602        1.1  blymn  */
    603        1.1  blymn int
    604        1.1  blymn set_field_back(FIELD *field, chtype attribute)
    605        1.1  blymn {
    606        1.1  blymn 	if (field == NULL)
    607        1.1  blymn 		_formi_default_field.back = attribute;
    608        1.1  blymn 	else
    609        1.1  blymn 		field->back = attribute;
    610        1.1  blymn 
    611        1.1  blymn 	return E_OK;
    612        1.1  blymn }
    613        1.1  blymn 
    614        1.1  blymn /*
    615       1.14  blymn  * Get the background character attribute for the given field.
    616       1.14  blymn  */
    617       1.14  blymn chtype
    618       1.14  blymn field_back(FIELD *field)
    619       1.14  blymn {
    620       1.14  blymn 	if (field == NULL)
    621       1.14  blymn 		return _formi_default_field.back;
    622       1.14  blymn 	else
    623       1.14  blymn 		return field->back;
    624       1.14  blymn }
    625       1.14  blymn 
    626       1.14  blymn /*
    627        1.1  blymn  * Set the pad character for the given field.
    628        1.1  blymn  */
    629        1.1  blymn int
    630        1.1  blymn set_field_pad(FIELD *field, int pad)
    631        1.1  blymn {
    632        1.1  blymn 	if (field == NULL)
    633        1.1  blymn 		_formi_default_field.pad = pad;
    634        1.1  blymn 	else
    635        1.1  blymn 		field->pad = pad;
    636        1.1  blymn 
    637        1.1  blymn 	return E_OK;
    638        1.1  blymn }
    639        1.1  blymn 
    640        1.1  blymn /*
    641        1.1  blymn  * Return the padding character for the given field.
    642        1.1  blymn  */
    643        1.1  blymn int
    644        1.1  blymn field_pad(FIELD *field)
    645        1.1  blymn {
    646        1.1  blymn 	if (field == NULL)
    647        1.1  blymn 		return _formi_default_field.pad;
    648        1.1  blymn 	else
    649        1.1  blymn 		return field->pad;
    650        1.1  blymn }
    651        1.1  blymn 
    652        1.1  blymn /*
    653        1.1  blymn  * Set the field initialisation function hook.
    654        1.1  blymn  */
    655        1.1  blymn int
    656        1.1  blymn set_field_init(FORM *form, Form_Hook function)
    657        1.1  blymn {
    658        1.1  blymn 	if (form == NULL)
    659        1.1  blymn 		_formi_default_form.field_init = function;
    660        1.1  blymn 	else
    661        1.1  blymn 		form->field_init = function;
    662        1.1  blymn 
    663        1.1  blymn 	return E_OK;
    664        1.1  blymn }
    665        1.1  blymn 
    666        1.1  blymn /*
    667        1.1  blymn  * Return the function hook for the field initialisation.
    668        1.1  blymn  */
    669        1.1  blymn Form_Hook
    670        1.1  blymn field_init(FORM *form)
    671        1.1  blymn {
    672        1.1  blymn 	if (form == NULL)
    673        1.1  blymn 		return _formi_default_form.field_init;
    674        1.1  blymn 	else
    675        1.1  blymn 		return form->field_init;
    676        1.1  blymn }
    677        1.1  blymn 
    678        1.1  blymn /*
    679        1.1  blymn  * Set the field termination function hook.
    680        1.1  blymn  */
    681        1.1  blymn int
    682        1.1  blymn set_field_term(FORM *form, Form_Hook function)
    683        1.1  blymn {
    684        1.1  blymn 	if (form == NULL)
    685        1.1  blymn 		_formi_default_form.field_term = function;
    686        1.1  blymn 	else
    687        1.1  blymn 		form->field_term = function;
    688        1.1  blymn 
    689        1.1  blymn 	return E_OK;
    690        1.1  blymn }
    691        1.1  blymn 
    692        1.1  blymn /*
    693        1.1  blymn  * Return the function hook defined for the field termination.
    694        1.1  blymn  */
    695        1.1  blymn Form_Hook
    696        1.1  blymn field_term(FORM *form)
    697        1.1  blymn {
    698        1.1  blymn 	if (form == NULL)
    699        1.1  blymn 		return _formi_default_form.field_term;
    700        1.1  blymn 	else
    701        1.1  blymn 		return form->field_term;
    702        1.1  blymn }
    703        1.1  blymn 
    704        1.1  blymn /*
    705        1.1  blymn  * Set the page flag on the given field to indicate it is the start of a
    706        1.1  blymn  * new page.
    707        1.1  blymn  */
    708        1.1  blymn int
    709        1.1  blymn set_new_page(FIELD *fptr, int page)
    710        1.1  blymn {
    711        1.1  blymn 	FIELD *field = (fptr == NULL)? &_formi_default_field : fptr;
    712        1.1  blymn 
    713        1.1  blymn 	if (field->parent != NULL) /* check if field is connected to a form */
    714        1.1  blymn 		return E_CONNECTED;
    715        1.1  blymn 
    716        1.1  blymn 	field->page_break = (page != FALSE);
    717        1.1  blymn 	return E_OK;
    718        1.1  blymn }
    719        1.1  blymn 
    720        1.1  blymn /*
    721        1.1  blymn  * Return the page status for the given field.  TRUE is returned if the
    722        1.1  blymn  * field is the start of a new page.
    723        1.1  blymn  */
    724        1.1  blymn int
    725        1.1  blymn new_page(FIELD *field)
    726        1.1  blymn {
    727        1.1  blymn 	if (field == NULL)
    728        1.1  blymn 		return _formi_default_field.page_break;
    729        1.1  blymn 	else
    730        1.1  blymn 		return field->page_break;
    731        1.1  blymn }
    732        1.1  blymn 
    733        1.1  blymn /*
    734        1.1  blymn  * Return the index of the field in the form fields array.
    735        1.1  blymn  */
    736        1.1  blymn int
    737        1.1  blymn field_index(FIELD *field)
    738        1.1  blymn {
    739        1.1  blymn 	if (field == NULL)
    740       1.14  blymn 		return E_BAD_ARGUMENT;
    741        1.1  blymn 
    742        1.1  blymn 	if (field->parent == NULL)
    743       1.14  blymn 		return E_NOT_CONNECTED;
    744        1.1  blymn 
    745        1.1  blymn 	return field->index;
    746        1.1  blymn }
    747        1.1  blymn 
    748        1.1  blymn /*
    749        1.1  blymn  * Internal function that does most of the work to create a new field.
    750        1.1  blymn  * The new field is initialised from the information in the prototype
    751        1.1  blymn  * field passed.
    752        1.1  blymn  * Returns NULL on error.
    753        1.1  blymn  */
    754        1.1  blymn static FIELD *
    755        1.1  blymn _formi_create_field(FIELD *prototype, int rows, int cols, int frow,
    756        1.1  blymn 		    int fcol, int nrows, int nbuf)
    757        1.1  blymn {
    758        1.1  blymn 	FIELD *new;
    759        1.1  blymn 
    760        1.1  blymn 	if ((rows <= 0) || (cols <= 0) || (frow < 0) || (fcol < 0) ||
    761        1.1  blymn 	    (nrows < 0) || (nbuf < 0))
    762        1.1  blymn 		return NULL;
    763        1.1  blymn 
    764        1.1  blymn 	if ((new = (FIELD *)malloc(sizeof(FIELD))) == NULL) {
    765        1.1  blymn 		return NULL;
    766        1.1  blymn 	}
    767        1.1  blymn 
    768        1.1  blymn 	  /* copy in the default field info */
    769        1.1  blymn 	bcopy(prototype, new, sizeof(FIELD));
    770        1.1  blymn 
    771        1.1  blymn 	new->nbuf = nbuf + 1;
    772        1.1  blymn 	new->rows = rows;
    773        1.1  blymn 	new->cols = cols;
    774        1.1  blymn 	new->form_row = frow;
    775        1.1  blymn 	new->form_col = fcol;
    776        1.1  blymn 	new->nrows = nrows;
    777        1.1  blymn 	new->link = new;
    778        1.1  blymn 	return new;
    779        1.1  blymn }
    780        1.1  blymn 
    781        1.1  blymn /*
    782        1.1  blymn  * Create a new field structure.
    783        1.1  blymn  */
    784        1.1  blymn FIELD *
    785        1.1  blymn new_field(int rows, int cols, int frow, int fcol, int nrows, int nbuf)
    786        1.1  blymn {
    787        1.1  blymn 	FIELD *new;
    788        1.1  blymn 	size_t buf_len;
    789        1.1  blymn 	int i;
    790        1.1  blymn 
    791        1.1  blymn 
    792        1.1  blymn 	if ((new = _formi_create_field(&_formi_default_field, rows, cols,
    793        1.1  blymn 				       frow, fcol, nrows, nbuf)) == NULL)
    794        1.1  blymn 		return NULL;
    795        1.1  blymn 
    796        1.1  blymn 	buf_len = (nbuf + 1) * sizeof(FORM_STR);
    797        1.1  blymn 
    798        1.1  blymn 	if ((new->buffers = (FORM_STR *)malloc(buf_len)) == NULL) {
    799        1.1  blymn 		free(new);
    800        1.1  blymn 		return NULL;
    801        1.1  blymn 	}
    802        1.1  blymn 
    803        1.4  blymn 	  /* Initialise the strings to a zero length string */
    804        1.1  blymn 	for (i = 0; i < nbuf + 1; i++) {
    805        1.4  blymn 		if ((new->buffers[i].string =
    806       1.10  blymn 		     (char *) malloc(sizeof(char))) == NULL) {
    807       1.10  blymn 			free(new->buffers);
    808       1.10  blymn 			free(new);
    809        1.4  blymn 			return NULL;
    810       1.10  blymn 		}
    811        1.4  blymn 		new->buffers[i].string[0] = '\0';
    812        1.1  blymn 		new->buffers[i].length = 0;
    813        1.4  blymn 		new->buffers[i].allocated = 1;
    814        1.1  blymn 	}
    815       1.10  blymn 
    816       1.25    roy 	if ((new->alines = (_FORMI_FIELD_LINES *)
    817       1.10  blymn 	     malloc(sizeof(struct _formi_field_lines))) == NULL) {
    818       1.10  blymn 		free(new->buffers);
    819       1.10  blymn 		free(new);
    820       1.10  blymn 		return NULL;
    821       1.10  blymn 	}
    822       1.10  blymn 
    823       1.25    roy 	new->alines->prev = NULL;
    824       1.25    roy 	new->alines->next = NULL;
    825       1.25    roy 	new->alines->allocated = 0;
    826       1.25    roy 	new->alines->length = 0;
    827       1.25    roy 	new->alines->expanded = 0;
    828       1.25    roy 	new->alines->string = NULL;
    829       1.25    roy 	new->alines->hard_ret = FALSE;
    830       1.25    roy 	new->alines->tabs = NULL;
    831       1.25    roy 	new->start_line = new->alines;
    832       1.25    roy 	new->cur_line = new->alines;
    833        1.1  blymn 
    834        1.1  blymn 	return new;
    835        1.1  blymn }
    836        1.1  blymn 
    837        1.1  blymn /*
    838        1.1  blymn  * Duplicate the given field, including it's buffers.
    839        1.1  blymn  */
    840        1.1  blymn FIELD *
    841        1.1  blymn dup_field(FIELD *field, int frow, int fcol)
    842        1.1  blymn {
    843        1.1  blymn 	FIELD *new;
    844        1.1  blymn 	size_t row_len, buf_len;
    845        1.1  blymn 
    846        1.1  blymn 	if (field == NULL)
    847        1.1  blymn 		return NULL;
    848       1.14  blymn 
    849       1.14  blymn 	  /* XXXX this right???? */
    850        1.1  blymn 	if ((new = _formi_create_field(field, (int) field->rows,
    851        1.1  blymn 				       (int ) field->cols,
    852        1.1  blymn 				       frow, fcol, (int) field->nrows,
    853        1.1  blymn 				       field->nbuf - 1)) == NULL)
    854        1.1  blymn 		return NULL;
    855        1.1  blymn 
    856        1.1  blymn 	row_len = (field->rows + field->nrows + 1) * field->cols;
    857        1.1  blymn 	buf_len = (field->nbuf + 1) * row_len * sizeof(FORM_STR);
    858        1.1  blymn 
    859        1.1  blymn 	if ((new->buffers = (FORM_STR *)malloc(buf_len)) == NULL) {
    860        1.1  blymn 		free(new);
    861        1.1  blymn 		return NULL;
    862        1.1  blymn 	}
    863        1.1  blymn 
    864        1.1  blymn 	  /* copy the buffers from the source field into the new copy */
    865        1.1  blymn 	bcopy(field->buffers, new->buffers, buf_len);
    866        1.1  blymn 
    867        1.1  blymn 	return new;
    868        1.1  blymn }
    869        1.1  blymn 
    870        1.1  blymn /*
    871        1.1  blymn  * Create a new field at the specified location by duplicating the given
    872        1.1  blymn  * field.  The buffers are shared with the parent field.
    873        1.1  blymn  */
    874        1.1  blymn FIELD *
    875        1.1  blymn link_field(FIELD *field, int frow, int fcol)
    876        1.1  blymn {
    877        1.1  blymn 	FIELD *new;
    878        1.1  blymn 
    879        1.1  blymn 	if (field == NULL)
    880        1.1  blymn 		return NULL;
    881        1.1  blymn 
    882        1.1  blymn 	if ((new = _formi_create_field(field, (int) field->rows,
    883        1.1  blymn 				       (int) field->cols,
    884        1.1  blymn 				       frow, fcol, (int) field->nrows,
    885        1.1  blymn 				       field->nbuf - 1)) == NULL)
    886        1.1  blymn 		return NULL;
    887        1.1  blymn 
    888        1.1  blymn 	new->link = field->link;
    889        1.1  blymn 	field->link = new;
    890        1.1  blymn 
    891        1.1  blymn 	  /* we are done.  The buffer pointer was copied during the field
    892        1.1  blymn 	     creation. */
    893        1.1  blymn 	return new;
    894        1.1  blymn }
    895        1.1  blymn 
    896        1.1  blymn /*
    897        1.1  blymn  * Release all storage allocated to the field
    898        1.1  blymn  */
    899        1.1  blymn int
    900        1.1  blymn free_field(FIELD *field)
    901        1.1  blymn {
    902        1.1  blymn 	FIELD *flink;
    903       1.15  blymn 	int i;
    904       1.15  blymn 	_formi_tab_t *ts, *nts;
    905        1.1  blymn 
    906        1.1  blymn 	if (field == NULL)
    907        1.1  blymn 		return E_BAD_ARGUMENT;
    908        1.1  blymn 
    909        1.1  blymn 	if (field->parent != NULL)
    910        1.1  blymn 		return E_CONNECTED;
    911        1.1  blymn 
    912        1.1  blymn 	if (field->link == field) { /* check if field linked */
    913        1.1  blymn 		  /* no it is not - release the buffers */
    914        1.1  blymn 		free(field->buffers);
    915       1.15  blymn 		  /* free the tab structures */
    916       1.15  blymn 		for (i = 0; i < field->row_count - 1; i++) {
    917       1.25    roy 			if (field->alines[i].tabs != NULL) {
    918       1.25    roy 				ts = field->alines[i].tabs;
    919       1.15  blymn 				while (ts != NULL) {
    920       1.15  blymn 					nts = ts->fwd;
    921       1.15  blymn 					free(ts);
    922       1.15  blymn 					ts = nts;
    923       1.15  blymn 				}
    924       1.15  blymn 			}
    925       1.15  blymn 		}
    926        1.1  blymn 	} else {
    927        1.1  blymn 		  /* is linked, traverse the links to find the field referring
    928        1.1  blymn 		   * to the one to be freed.
    929        1.1  blymn 		   */
    930        1.1  blymn 		for (flink = field->link; flink != field; flink = flink->link);
    931        1.1  blymn 		flink->link = field->link;
    932        1.1  blymn 	}
    933        1.1  blymn 
    934        1.1  blymn 	free(field);
    935        1.1  blymn 	return E_OK;
    936        1.1  blymn }
    937        1.1  blymn 
    938        1.1  blymn 
    939