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