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@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 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