field.c revision 1.5
1/* $NetBSD: field.c,v 1.5 2001/02/03 12:35:14 blymn Exp $ */ 2/*- 3 * Copyright (c) 1998-1999 Brett Lymn 4 * (blymn@baea.com.au, brett_lymn@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 36extern FORM _formi_default_form; 37 38FIELD _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, /* amount of horizontal scroll... */ 55 0, /* number of rows actually used in field */ 56 0, /* x pos of cursor in field */ 57 0, /* y pos of cursor in field */ 58 0, /* start of a new page on the form if 1 */ 59 0, /* number of the page this field is on */ 60 A_NORMAL, /* character attributes for the foreground */ 61 A_NORMAL, /* character attributes for the background */ 62 ' ', /* padding character */ 63 DEFAULT_FORM_OPTS, /* options for the field */ 64 NULL, /* the form this field is bound to, if any */ 65 NULL, /* field above this one */ 66 NULL, /* field below this one */ 67 NULL, /* field to the left of this one */ 68 NULL, /* field to the right of this one */ 69 NULL, /* user defined pointer. */ 70 NULL, /* used if fields are linked */ 71 NULL, /* type struct for the field */ 72 {NULL, NULL}, /* circle queue glue for sorting fields */ 73 NULL, /* args for field type. */ 74 NULL, /* array of buffers for the field */ 75}; 76 77/* internal function prototypes */ 78static FIELD * 79_formi_create_field(FIELD *, int, int, int, int, int, int); 80 81 82/* 83 * Set the userptr for the field 84 */ 85int 86set_field_userptr(FIELD *field, void *ptr) 87{ 88 FIELD *fp = (field == NULL) ? &_formi_default_field : field; 89 90 fp->userptr = ptr; 91 92 return E_OK; 93} 94 95/* 96 * Return the userptr for the field. 97 */ 98 99void * 100field_userptr(FIELD *field) 101{ 102 if (field == NULL) 103 return _formi_default_field.userptr; 104 else 105 return field->userptr; 106} 107 108/* 109 * Set the options for the designated field. 110 */ 111int 112set_field_opts(FIELD *field, Form_Options options) 113{ 114 FIELD *fp = (field == NULL) ? &_formi_default_field : field; 115 116 fp->opts = options; 117 118 return E_OK; 119} 120 121/* 122 * Turn on the passed field options. 123 */ 124int 125field_opts_on(FIELD *field, Form_Options options) 126{ 127 FIELD *fp = (field == NULL) ? &_formi_default_field : field; 128 129 fp->opts |= options; 130 131 return E_OK; 132} 133 134/* 135 * Turn off the passed field options. 136 */ 137int 138field_opts_off(FIELD *field, Form_Options options) 139{ 140 FIELD *fp = (field == NULL) ? &_formi_default_field : field; 141 142 fp->opts &= ~options; 143 return E_OK; 144} 145 146/* 147 * Return the field options associated with the passed field. 148 */ 149Form_Options 150field_opts(FIELD *field) 151{ 152 if (field == NULL) 153 return _formi_default_field.opts; 154 else 155 return field->opts; 156} 157 158/* 159 * Set the justification for the passed field. 160 */ 161int 162set_field_just(FIELD *field, int justification) 163{ 164 FIELD *fp = (field == NULL) ? &_formi_default_field : field; 165 166 if ((justification < MIN_JUST_STYLE) /* check justification valid */ 167 || (justification > MAX_JUST_STYLE)) 168 return E_BAD_ARGUMENT; 169 170 fp->justification = justification; 171 return E_OK; 172} 173 174/* 175 * Return the justification style of the field passed. 176 */ 177int 178field_just(FIELD *field) 179{ 180 if (field == NULL) 181 return _formi_default_field.justification; 182 else 183 return field->justification; 184} 185 186/* 187 * Return information about the field passed. 188 */ 189int 190field_info(FIELD *field, int *rows, int *cols, int *frow, int *fcol, 191 int *nrow, int *nbuf) 192{ 193 if (field == NULL) 194 return E_BAD_ARGUMENT; 195 196 *rows = field->rows; 197 *cols = field->cols; 198 *frow = field->form_row; 199 *fcol = field->form_col; 200 *nrow = field->nrows; 201 *nbuf = field->nbuf; 202 203 return E_OK; 204} 205 206/* 207 * Report the dynamic field information. 208 */ 209int 210dynamic_field_info(FIELD *field, int *drows, int *dcols, int *max) 211{ 212 if (field == NULL) 213 return E_BAD_ARGUMENT; 214 215 if ((field->opts & O_STATIC) == O_STATIC) /* check if field dynamic */ 216 return E_BAD_ARGUMENT; 217 218 *drows = field->drows; 219 *dcols = field->dcols; 220 *max = field->max; 221 222 return E_OK; 223} 224 225/* 226 * Set the value of the field buffer to the value given. 227 */ 228 229int 230set_field_buffer(FIELD *field, int buffer, char *value) 231{ 232 unsigned len; 233 int status; 234 235 if (field == NULL) 236 return E_BAD_ARGUMENT; 237 238 if (buffer >= field->nbuf) /* make sure buffer is valid */ 239 return E_BAD_ARGUMENT; 240 241 len = strlen(value); 242 if ((field->buffers[buffer].string = (char *) realloc(field->buffers[buffer].string, 243 len + 1)) == NULL) 244 return E_SYSTEM_ERROR; 245 246 strcpy(field->buffers[buffer].string, value); 247 field->buffers[buffer].length = len; 248 field->buffers[buffer].allocated = len + 1; 249 field->row_count = 1; /* must be at least one row */ 250 251 /* we have to hope the wrap works - if it does not then the 252 buffer is pretty much borked */ 253 status = _formi_wrap_field(field, 0); 254 if (status != E_OK) 255 return status; 256 257 /* redraw the field to reflect the new contents. If the field 258 * is attached.... 259 */ 260 if (field->parent != NULL) 261 _formi_redraw_field(field->parent, field->index); 262 263 return E_OK; 264} 265 266/* 267 * Return the requested field buffer to the caller. 268 */ 269char * 270field_buffer(FIELD *field, int buffer) 271{ 272 273 if (field == NULL) 274 return NULL; 275 276 if (buffer >= field->nbuf) 277 return NULL; 278 279 return field->buffers[buffer].string; 280} 281 282/* 283 * Set the buffer 0 field status. 284 */ 285int 286set_field_status(FIELD *field, int status) 287{ 288 289 if (field == NULL) 290 return E_BAD_ARGUMENT; 291 292 if (status != FALSE) 293 field->buf0_status = TRUE; 294 else 295 field->buf0_status = FALSE; 296 297 return E_OK; 298} 299 300/* 301 * Return the buffer 0 status flag for the given field. 302 */ 303int 304field_status(FIELD *field) 305{ 306 307 if (field == NULL) /* the default buffer 0 never changes :-) */ 308 return FALSE; 309 310 return field->buf0_status; 311} 312 313/* 314 * Set the maximum growth for a dynamic field. 315 */ 316int 317set_max_field(FIELD *fptr, int max) 318{ 319 FIELD *field = (field == NULL)? &_formi_default_field : fptr; 320 321 if ((field->opts & O_STATIC) == O_STATIC) /* check if field dynamic */ 322 return E_BAD_ARGUMENT; 323 324 if (max < 0) /* negative numbers are bad.... */ 325 return E_BAD_ARGUMENT; 326 327 field->max = max; 328 return E_OK; 329} 330 331/* 332 * Set the field foreground character attributes. 333 */ 334int 335set_field_fore(FIELD *fptr, chtype attribute) 336{ 337 FIELD *field = (fptr == NULL)? &_formi_default_field : fptr; 338 339 field->fore = attribute; 340 return E_OK; 341} 342 343/* 344 * Return the foreground character attribute for the given field. 345 */ 346chtype 347field_fore(FIELD *field) 348{ 349 if (field == NULL) 350 return _formi_default_field.fore; 351 else 352 return field->fore; 353} 354 355/* 356 * Set the background character attribute for the given field. 357 */ 358int 359set_field_back(FIELD *field, chtype attribute) 360{ 361 if (field == NULL) 362 _formi_default_field.back = attribute; 363 else 364 field->back = attribute; 365 366 return E_OK; 367} 368 369/* 370 * Set the pad character for the given field. 371 */ 372int 373set_field_pad(FIELD *field, int pad) 374{ 375 if (field == NULL) 376 _formi_default_field.pad = pad; 377 else 378 field->pad = pad; 379 380 return E_OK; 381} 382 383/* 384 * Return the padding character for the given field. 385 */ 386int 387field_pad(FIELD *field) 388{ 389 if (field == NULL) 390 return _formi_default_field.pad; 391 else 392 return field->pad; 393} 394 395/* 396 * Set the field initialisation function hook. 397 */ 398int 399set_field_init(FORM *form, Form_Hook function) 400{ 401 if (form == NULL) 402 _formi_default_form.field_init = function; 403 else 404 form->field_init = function; 405 406 return E_OK; 407} 408 409/* 410 * Return the function hook for the field initialisation. 411 */ 412Form_Hook 413field_init(FORM *form) 414{ 415 if (form == NULL) 416 return _formi_default_form.field_init; 417 else 418 return form->field_init; 419} 420 421/* 422 * Set the field termination function hook. 423 */ 424int 425set_field_term(FORM *form, Form_Hook function) 426{ 427 if (form == NULL) 428 _formi_default_form.field_term = function; 429 else 430 form->field_term = function; 431 432 return E_OK; 433} 434 435/* 436 * Return the function hook defined for the field termination. 437 */ 438Form_Hook 439field_term(FORM *form) 440{ 441 if (form == NULL) 442 return _formi_default_form.field_term; 443 else 444 return form->field_term; 445} 446 447/* 448 * Set the page flag on the given field to indicate it is the start of a 449 * new page. 450 */ 451int 452set_new_page(FIELD *fptr, int page) 453{ 454 FIELD *field = (fptr == NULL)? &_formi_default_field : fptr; 455 456 if (field->parent != NULL) /* check if field is connected to a form */ 457 return E_CONNECTED; 458 459 field->page_break = (page != FALSE); 460 return E_OK; 461} 462 463/* 464 * Return the page status for the given field. TRUE is returned if the 465 * field is the start of a new page. 466 */ 467int 468new_page(FIELD *field) 469{ 470 if (field == NULL) 471 return _formi_default_field.page_break; 472 else 473 return field->page_break; 474} 475 476/* 477 * Return the index of the field in the form fields array. 478 */ 479int 480field_index(FIELD *field) 481{ 482 if (field == NULL) 483 return -1; 484 485 if (field->parent == NULL) 486 return -1; 487 488 return field->index; 489} 490 491/* 492 * Internal function that does most of the work to create a new field. 493 * The new field is initialised from the information in the prototype 494 * field passed. 495 * Returns NULL on error. 496 */ 497static FIELD * 498_formi_create_field(FIELD *prototype, int rows, int cols, int frow, 499 int fcol, int nrows, int nbuf) 500{ 501 FIELD *new; 502 503 if ((rows <= 0) || (cols <= 0) || (frow < 0) || (fcol < 0) || 504 (nrows < 0) || (nbuf < 0)) 505 return NULL; 506 507 if ((new = (FIELD *)malloc(sizeof(FIELD))) == NULL) { 508 return NULL; 509 } 510 511 /* copy in the default field info */ 512 bcopy(prototype, new, sizeof(FIELD)); 513 514 new->nbuf = nbuf + 1; 515 new->rows = rows; 516 new->cols = cols; 517 new->form_row = frow; 518 new->form_col = fcol; 519 new->nrows = nrows; 520 new->link = new; 521 return new; 522} 523 524/* 525 * Create a new field structure. 526 */ 527FIELD * 528new_field(int rows, int cols, int frow, int fcol, int nrows, int nbuf) 529{ 530 FIELD *new; 531 size_t buf_len; 532 int i; 533 534 535 if ((new = _formi_create_field(&_formi_default_field, rows, cols, 536 frow, fcol, nrows, nbuf)) == NULL) 537 return NULL; 538 539 buf_len = (nbuf + 1) * sizeof(FORM_STR); 540 541 if ((new->buffers = (FORM_STR *)malloc(buf_len)) == NULL) { 542 free(new); 543 return NULL; 544 } 545 546 /* Initialise the strings to a zero length string */ 547 for (i = 0; i < nbuf + 1; i++) { 548 if ((new->buffers[i].string = 549 (char *) malloc(sizeof(char))) == NULL) 550 return NULL; 551 new->buffers[i].string[0] = '\0'; 552 new->buffers[i].length = 0; 553 new->buffers[i].allocated = 1; 554 } 555 556 return new; 557} 558 559/* 560 * Duplicate the given field, including it's buffers. 561 */ 562FIELD * 563dup_field(FIELD *field, int frow, int fcol) 564{ 565 FIELD *new; 566 size_t row_len, buf_len; 567 568 if (field == NULL) 569 return NULL; 570 571 if ((new = _formi_create_field(field, (int) field->rows, 572 (int ) field->cols, 573 frow, fcol, (int) field->nrows, 574 field->nbuf - 1)) == NULL) 575 return NULL; 576 577 row_len = (field->rows + field->nrows + 1) * field->cols; 578 buf_len = (field->nbuf + 1) * row_len * sizeof(FORM_STR); 579 580 if ((new->buffers = (FORM_STR *)malloc(buf_len)) == NULL) { 581 free(new); 582 return NULL; 583 } 584 585 /* copy the buffers from the source field into the new copy */ 586 bcopy(field->buffers, new->buffers, buf_len); 587 588 return new; 589} 590 591/* 592 * Create a new field at the specified location by duplicating the given 593 * field. The buffers are shared with the parent field. 594 */ 595FIELD * 596link_field(FIELD *field, int frow, int fcol) 597{ 598 FIELD *new; 599 600 if (field == NULL) 601 return NULL; 602 603 if ((new = _formi_create_field(field, (int) field->rows, 604 (int) field->cols, 605 frow, fcol, (int) field->nrows, 606 field->nbuf - 1)) == NULL) 607 return NULL; 608 609 new->link = field->link; 610 field->link = new; 611 612 /* we are done. The buffer pointer was copied during the field 613 creation. */ 614 return new; 615} 616 617/* 618 * Release all storage allocated to the field 619 */ 620int 621free_field(FIELD *field) 622{ 623 FIELD *flink; 624 625 if (field == NULL) 626 return E_BAD_ARGUMENT; 627 628 if (field->parent != NULL) 629 return E_CONNECTED; 630 631 if (field->link == field) { /* check if field linked */ 632 /* no it is not - release the buffers */ 633 free(field->buffers); 634 } else { 635 /* is linked, traverse the links to find the field referring 636 * to the one to be freed. 637 */ 638 for (flink = field->link; flink != field; flink = flink->link); 639 flink->link = field->link; 640 } 641 642 free(field); 643 return E_OK; 644} 645 646 647