Home | History | Annotate | Line # | Download | only in libform
field.c revision 1.9
      1 /*	$NetBSD: field.c,v 1.9 2001/04/06 05:24:59 blymn Exp $	*/
      2 /*-
      3  * Copyright (c) 1998-1999 Brett Lymn
      4  *                         (blymn (at) baea.com.au, brett_lymn (at) yahoo.com.au)
      5  * All rights reserved.
      6  *
      7  * This code has been donated to The NetBSD Foundation by the Author.
      8  *
      9  * Redistribution and use in source and binary forms, with or without
     10  * modification, are permitted provided that the following conditions
     11  * are met:
     12  * 1. Redistributions of source code must retain the above copyright
     13  *    notice, this list of conditions and the following disclaimer.
     14  * 2. The name of the author may not be used to endorse or promote products
     15  *    derived from this software withough specific prior written permission
     16  *
     17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
     18  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     19  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
     20  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
     21  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
     22  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     23  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     24  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
     26  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     27  *
     28  *
     29  */
     30 
     31 #include <stdlib.h>
     32 #include <strings.h>
     33 #include <form.h>
     34 #include "internals.h"
     35 
     36 extern FORM _formi_default_form;
     37 
     38 FIELD _formi_default_field = {
     39 	0, /* rows in the field */
     40 	0, /* columns in the field */
     41 	0, /* dynamic rows */
     42 	0, /* dynamic columns */
     43 	0, /* maximum growth */
     44 	0, /* starting row in the form subwindow */
     45 	0, /* starting column in the form subwindow */
     46 	0, /* number of off screen rows */
     47 	0, /* index of this field in form fields array. */
     48 	0, /* number of buffers associated with this field */
     49 	FALSE, /* set to true if buffer 0 has changed. */
     50 	NO_JUSTIFICATION, /* justification style of the field */
     51 	FALSE, /* set to true if field is in overlay mode */
     52 	0, /* starting char in string (horiz scroll) */
     53 	0, /* starting line in field (vert scroll) */
     54 	0, /* number of rows actually used in field */
     55 	0, /* x pos of cursor in field */
     56 	0, /* y pos of cursor in field */
     57 	0, /* start of a new page on the form if 1 */
     58 	0, /* number of the page this field is on */
     59 	A_NORMAL, /* character attributes for the foreground */
     60 	A_NORMAL, /* character attributes for the background */
     61 	' ', /* padding character */
     62 	DEFAULT_FORM_OPTS, /* options for the field */
     63 	NULL, /* the form this field is bound to, if any */
     64 	NULL, /* field above this one */
     65 	NULL, /* field below this one */
     66 	NULL, /* field to the left of this one */
     67 	NULL, /* field to the right of this one */
     68 	NULL,  /* user defined pointer. */
     69 	NULL, /* used if fields are linked */
     70 	NULL, /* type struct for the field */
     71 	{NULL, NULL}, /* circle queue glue for sorting fields */
     72 	NULL, /* args for field type. */
     73 	NULL, /* array of buffers for the field */
     74 };
     75 
     76 /* internal function prototypes */
     77 static FIELD *
     78 _formi_create_field(FIELD *, int, int, int, int, int, int);
     79 
     80 
     81 /*
     82  * Set the userptr for the field
     83  */
     84 int
     85 set_field_userptr(FIELD *field, void *ptr)
     86 {
     87 	FIELD *fp = (field == NULL) ? &_formi_default_field : field;
     88 
     89 	fp->userptr = ptr;
     90 
     91 	return E_OK;
     92 }
     93 
     94 /*
     95  * Return the userptr for the field.
     96  */
     97 
     98 void *
     99 field_userptr(FIELD *field)
    100 {
    101 	if (field == NULL)
    102 		return _formi_default_field.userptr;
    103 	else
    104 		return field->userptr;
    105 }
    106 
    107 /*
    108  * Set the options for the designated field.
    109  */
    110 int
    111 set_field_opts(FIELD *field, Form_Options options)
    112 {
    113 	int i;
    114 
    115 	FIELD *fp = (field == NULL) ? &_formi_default_field : field;
    116 
    117 	  /* not allowed to set opts if the field is the current one */
    118 	if ((field != NULL) && (field->parent != NULL) &&
    119 	    (field->parent->cur_field == field->index))
    120 		return E_CURRENT;
    121 
    122 	if ((options & O_STATIC) == O_STATIC) {
    123 		for (i = 0; i < field->nbuf; i++) {
    124 			if (field->buffers[i].length > field->cols)
    125 				field->buffers[i].string[field->cols] = '\0';
    126 		}
    127 	}
    128 
    129 	fp->opts = options;
    130 
    131 	return E_OK;
    132 }
    133 
    134 /*
    135  * Turn on the passed field options.
    136  */
    137 int
    138 field_opts_on(FIELD *field, Form_Options options)
    139 {
    140 	int i;
    141 
    142 	FIELD *fp = (field == NULL) ? &_formi_default_field : field;
    143 
    144 	  /* not allowed to set opts if the field is the current one */
    145 	if ((field != NULL) && (field->parent != NULL) &&
    146 	    (field->parent->cur_field == field->index))
    147 		return E_CURRENT;
    148 
    149 	if ((options & O_STATIC) == O_STATIC) {
    150 		for (i = 0; i < field->nbuf; i++) {
    151 			if (field->buffers[i].length > field->cols)
    152 				field->buffers[i].string[field->cols] = '\0';
    153 		}
    154 	}
    155 
    156 	fp->opts |= options;
    157 
    158 	return E_OK;
    159 }
    160 
    161 /*
    162  * Turn off the passed field options.
    163  */
    164 int
    165 field_opts_off(FIELD *field, Form_Options options)
    166 {
    167 	FIELD *fp = (field == NULL) ? &_formi_default_field : field;
    168 
    169 	  /* not allowed to set opts if the field is the current one */
    170 	if ((field != NULL) && (field->parent != NULL) &&
    171 	    (field->parent->cur_field == field->index))
    172 		return E_CURRENT;
    173 
    174 	fp->opts &= ~options;
    175 	return E_OK;
    176 }
    177 
    178 /*
    179  * Return the field options associated with the passed field.
    180  */
    181 Form_Options
    182 field_opts(FIELD *field)
    183 {
    184 	if (field == NULL)
    185 		return _formi_default_field.opts;
    186 	else
    187 		return field->opts;
    188 }
    189 
    190 /*
    191  * Set the justification for the passed field.
    192  */
    193 int
    194 set_field_just(FIELD *field, int justification)
    195 {
    196 	FIELD *fp = (field == NULL) ? &_formi_default_field : field;
    197 
    198 	  /*
    199 	   * not allowed to set justification if the field is
    200 	   * the current one
    201 	   */
    202 	if ((field != NULL) && (field->parent != NULL) &&
    203 	    (field->parent->cur_field == field->index))
    204 		return E_CURRENT;
    205 
    206 	if ((justification < MIN_JUST_STYLE) /* check justification valid */
    207 	    || (justification > MAX_JUST_STYLE))
    208 		return E_BAD_ARGUMENT;
    209 
    210 	fp->justification = justification;
    211 	return E_OK;
    212 }
    213 
    214 /*
    215  * Return the justification style of the field passed.
    216  */
    217 int
    218 field_just(FIELD *field)
    219 {
    220 	if (field == NULL)
    221 		return _formi_default_field.justification;
    222 	else
    223 		return field->justification;
    224 }
    225 
    226 /*
    227  * Return information about the field passed.
    228  */
    229 int
    230 field_info(FIELD *field, int *rows, int *cols, int *frow, int *fcol,
    231 	   int *nrow, int *nbuf)
    232 {
    233 	if (field == NULL)
    234 		return E_BAD_ARGUMENT;
    235 
    236 	*rows = field->rows;
    237 	*cols = field->cols;
    238 	*frow = field->form_row;
    239 	*fcol = field->form_col;
    240 	*nrow = field->nrows;
    241 	*nbuf = field->nbuf;
    242 
    243 	return E_OK;
    244 }
    245 
    246 /*
    247  * Report the dynamic field information.
    248  */
    249 int
    250 dynamic_field_info(FIELD *field, int *drows, int *dcols, int *max)
    251 {
    252 	if (field == NULL)
    253 		return E_BAD_ARGUMENT;
    254 
    255 	if ((field->opts & O_STATIC) == O_STATIC) {
    256 		*drows = field->rows;
    257 		*dcols = field->cols;
    258 	} else {
    259 		*drows = field->drows;
    260 		*dcols = field->dcols;
    261 	}
    262 
    263 	*max = field->max;
    264 
    265 	return E_OK;
    266 }
    267 
    268 /*
    269  * Set the value of the field buffer to the value given.
    270  */
    271 
    272 int
    273 set_field_buffer(FIELD *field, int buffer, char *value)
    274 {
    275 	unsigned len;
    276 	int status;
    277 
    278 	if (field == NULL)
    279 		return E_BAD_ARGUMENT;
    280 
    281 	if (buffer >= field->nbuf) /* make sure buffer is valid */
    282 		return E_BAD_ARGUMENT;
    283 
    284 	len = strlen(value);
    285 	if (((field->opts & O_STATIC) == O_STATIC) && (len > field->cols))
    286 		len = field->cols;
    287 
    288 	if ((field->buffers[buffer].string =
    289 	     (char *) realloc(field->buffers[buffer].string, len + 1)) == NULL)
    290 		return E_SYSTEM_ERROR;
    291 
    292 	strlcpy(field->buffers[buffer].string, value, len + 1);
    293 	field->buffers[buffer].length = len;
    294 	field->buffers[buffer].allocated = len + 1;
    295 	field->row_count = 1; /* must be at least one row */
    296 
    297 	  /* we have to hope the wrap works - if it does not then the
    298 	     buffer is pretty much borked */
    299 	status = _formi_wrap_field(field, 0);
    300 	if (status != E_OK)
    301 		return status;
    302 
    303 	  /* redraw the field to reflect the new contents. If the field
    304 	   * is attached....
    305 	   */
    306 	if (field->parent != NULL)
    307 		_formi_redraw_field(field->parent, field->index);
    308 
    309 	return E_OK;
    310 }
    311 
    312 /*
    313  * Return the requested field buffer to the caller.
    314  */
    315 char *
    316 field_buffer(FIELD *field, int buffer)
    317 {
    318 
    319 	if (field == NULL)
    320 		return NULL;
    321 
    322 	if (buffer >= field->nbuf)
    323 		return NULL;
    324 
    325 	return field->buffers[buffer].string;
    326 }
    327 
    328 /*
    329  * Set the buffer 0 field status.
    330  */
    331 int
    332 set_field_status(FIELD *field, int status)
    333 {
    334 
    335 	if (field == NULL)
    336 		return E_BAD_ARGUMENT;
    337 
    338 	if (status != FALSE)
    339 		field->buf0_status = TRUE;
    340 	else
    341 		field->buf0_status = FALSE;
    342 
    343 	return E_OK;
    344 }
    345 
    346 /*
    347  * Return the buffer 0 status flag for the given field.
    348  */
    349 int
    350 field_status(FIELD *field)
    351 {
    352 
    353 	if (field == NULL) /* the default buffer 0 never changes :-) */
    354 		return FALSE;
    355 
    356 	return field->buf0_status;
    357 }
    358 
    359 /*
    360  * Set the maximum growth for a dynamic field.
    361  */
    362 int
    363 set_max_field(FIELD *fptr, int max)
    364 {
    365 	FIELD *field = (field == NULL)? &_formi_default_field : fptr;
    366 
    367 	if ((field->opts & O_STATIC) == O_STATIC) /* check if field dynamic */
    368 		return E_BAD_ARGUMENT;
    369 
    370 	if (max < 0) /* negative numbers are bad.... */
    371 		return E_BAD_ARGUMENT;
    372 
    373 	field->max = max;
    374 	return E_OK;
    375 }
    376 
    377 /*
    378  * Set the field foreground character attributes.
    379  */
    380 int
    381 set_field_fore(FIELD *fptr, chtype attribute)
    382 {
    383 	FIELD *field = (fptr == NULL)? &_formi_default_field : fptr;
    384 
    385 	field->fore = attribute;
    386 	return E_OK;
    387 }
    388 
    389 /*
    390  * Return the foreground character attribute for the given field.
    391  */
    392 chtype
    393 field_fore(FIELD *field)
    394 {
    395 	if (field == NULL)
    396 		return _formi_default_field.fore;
    397 	else
    398 		return field->fore;
    399 }
    400 
    401 /*
    402  * Set the background character attribute for the given field.
    403  */
    404 int
    405 set_field_back(FIELD *field, chtype attribute)
    406 {
    407 	if (field == NULL)
    408 		_formi_default_field.back = attribute;
    409 	else
    410 		field->back = attribute;
    411 
    412 	return E_OK;
    413 }
    414 
    415 /*
    416  * Set the pad character for the given field.
    417  */
    418 int
    419 set_field_pad(FIELD *field, int pad)
    420 {
    421 	if (field == NULL)
    422 		_formi_default_field.pad = pad;
    423 	else
    424 		field->pad = pad;
    425 
    426 	return E_OK;
    427 }
    428 
    429 /*
    430  * Return the padding character for the given field.
    431  */
    432 int
    433 field_pad(FIELD *field)
    434 {
    435 	if (field == NULL)
    436 		return _formi_default_field.pad;
    437 	else
    438 		return field->pad;
    439 }
    440 
    441 /*
    442  * Set the field initialisation function hook.
    443  */
    444 int
    445 set_field_init(FORM *form, Form_Hook function)
    446 {
    447 	if (form == NULL)
    448 		_formi_default_form.field_init = function;
    449 	else
    450 		form->field_init = function;
    451 
    452 	return E_OK;
    453 }
    454 
    455 /*
    456  * Return the function hook for the field initialisation.
    457  */
    458 Form_Hook
    459 field_init(FORM *form)
    460 {
    461 	if (form == NULL)
    462 		return _formi_default_form.field_init;
    463 	else
    464 		return form->field_init;
    465 }
    466 
    467 /*
    468  * Set the field termination function hook.
    469  */
    470 int
    471 set_field_term(FORM *form, Form_Hook function)
    472 {
    473 	if (form == NULL)
    474 		_formi_default_form.field_term = function;
    475 	else
    476 		form->field_term = function;
    477 
    478 	return E_OK;
    479 }
    480 
    481 /*
    482  * Return the function hook defined for the field termination.
    483  */
    484 Form_Hook
    485 field_term(FORM *form)
    486 {
    487 	if (form == NULL)
    488 		return _formi_default_form.field_term;
    489 	else
    490 		return form->field_term;
    491 }
    492 
    493 /*
    494  * Set the page flag on the given field to indicate it is the start of a
    495  * new page.
    496  */
    497 int
    498 set_new_page(FIELD *fptr, int page)
    499 {
    500 	FIELD *field = (fptr == NULL)? &_formi_default_field : fptr;
    501 
    502 	if (field->parent != NULL) /* check if field is connected to a form */
    503 		return E_CONNECTED;
    504 
    505 	field->page_break = (page != FALSE);
    506 	return E_OK;
    507 }
    508 
    509 /*
    510  * Return the page status for the given field.  TRUE is returned if the
    511  * field is the start of a new page.
    512  */
    513 int
    514 new_page(FIELD *field)
    515 {
    516 	if (field == NULL)
    517 		return _formi_default_field.page_break;
    518 	else
    519 		return field->page_break;
    520 }
    521 
    522 /*
    523  * Return the index of the field in the form fields array.
    524  */
    525 int
    526 field_index(FIELD *field)
    527 {
    528 	if (field == NULL)
    529 		return -1;
    530 
    531 	if (field->parent == NULL)
    532 		return -1;
    533 
    534 	return field->index;
    535 }
    536 
    537 /*
    538  * Internal function that does most of the work to create a new field.
    539  * The new field is initialised from the information in the prototype
    540  * field passed.
    541  * Returns NULL on error.
    542  */
    543 static FIELD *
    544 _formi_create_field(FIELD *prototype, int rows, int cols, int frow,
    545 		    int fcol, int nrows, int nbuf)
    546 {
    547 	FIELD *new;
    548 
    549 	if ((rows <= 0) || (cols <= 0) || (frow < 0) || (fcol < 0) ||
    550 	    (nrows < 0) || (nbuf < 0))
    551 		return NULL;
    552 
    553 	if ((new = (FIELD *)malloc(sizeof(FIELD))) == NULL) {
    554 		return NULL;
    555 	}
    556 
    557 	  /* copy in the default field info */
    558 	bcopy(prototype, new, sizeof(FIELD));
    559 
    560 	new->nbuf = nbuf + 1;
    561 	new->rows = rows;
    562 	new->cols = cols;
    563 	new->form_row = frow;
    564 	new->form_col = fcol;
    565 	new->nrows = nrows;
    566 	new->link = new;
    567 	return new;
    568 }
    569 
    570 /*
    571  * Create a new field structure.
    572  */
    573 FIELD *
    574 new_field(int rows, int cols, int frow, int fcol, int nrows, int nbuf)
    575 {
    576 	FIELD *new;
    577 	size_t buf_len;
    578 	int i;
    579 
    580 
    581 	if ((new = _formi_create_field(&_formi_default_field, rows, cols,
    582 				       frow, fcol, nrows, nbuf)) == NULL)
    583 		return NULL;
    584 
    585 	buf_len = (nbuf + 1) * sizeof(FORM_STR);
    586 
    587 	if ((new->buffers = (FORM_STR *)malloc(buf_len)) == NULL) {
    588 		free(new);
    589 		return NULL;
    590 	}
    591 
    592 	  /* Initialise the strings to a zero length string */
    593 	for (i = 0; i < nbuf + 1; i++) {
    594 		if ((new->buffers[i].string =
    595 		     (char *) malloc(sizeof(char))) == NULL)
    596 			return NULL;
    597 		new->buffers[i].string[0] = '\0';
    598 		new->buffers[i].length = 0;
    599 		new->buffers[i].allocated = 1;
    600 	}
    601 
    602 	return new;
    603 }
    604 
    605 /*
    606  * Duplicate the given field, including it's buffers.
    607  */
    608 FIELD *
    609 dup_field(FIELD *field, int frow, int fcol)
    610 {
    611 	FIELD *new;
    612 	size_t row_len, buf_len;
    613 
    614 	if (field == NULL)
    615 		return NULL;
    616 
    617 	if ((new = _formi_create_field(field, (int) field->rows,
    618 				       (int ) field->cols,
    619 				       frow, fcol, (int) field->nrows,
    620 				       field->nbuf - 1)) == NULL)
    621 		return NULL;
    622 
    623 	row_len = (field->rows + field->nrows + 1) * field->cols;
    624 	buf_len = (field->nbuf + 1) * row_len * sizeof(FORM_STR);
    625 
    626 	if ((new->buffers = (FORM_STR *)malloc(buf_len)) == NULL) {
    627 		free(new);
    628 		return NULL;
    629 	}
    630 
    631 	  /* copy the buffers from the source field into the new copy */
    632 	bcopy(field->buffers, new->buffers, buf_len);
    633 
    634 	return new;
    635 }
    636 
    637 /*
    638  * Create a new field at the specified location by duplicating the given
    639  * field.  The buffers are shared with the parent field.
    640  */
    641 FIELD *
    642 link_field(FIELD *field, int frow, int fcol)
    643 {
    644 	FIELD *new;
    645 
    646 	if (field == NULL)
    647 		return NULL;
    648 
    649 	if ((new = _formi_create_field(field, (int) field->rows,
    650 				       (int) field->cols,
    651 				       frow, fcol, (int) field->nrows,
    652 				       field->nbuf - 1)) == NULL)
    653 		return NULL;
    654 
    655 	new->link = field->link;
    656 	field->link = new;
    657 
    658 	  /* we are done.  The buffer pointer was copied during the field
    659 	     creation. */
    660 	return new;
    661 }
    662 
    663 /*
    664  * Release all storage allocated to the field
    665  */
    666 int
    667 free_field(FIELD *field)
    668 {
    669 	FIELD *flink;
    670 
    671 	if (field == NULL)
    672 		return E_BAD_ARGUMENT;
    673 
    674 	if (field->parent != NULL)
    675 		return E_CONNECTED;
    676 
    677 	if (field->link == field) { /* check if field linked */
    678 		  /* no it is not - release the buffers */
    679 		free(field->buffers);
    680 	} else {
    681 		  /* is linked, traverse the links to find the field referring
    682 		   * to the one to be freed.
    683 		   */
    684 		for (flink = field->link; flink != field; flink = flink->link);
    685 		flink->link = field->link;
    686 	}
    687 
    688 	free(field);
    689 	return E_OK;
    690 }
    691 
    692 
    693