1 /* $NetBSD: field.c,v 1.7 2001/02/16 03:19:32 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, /* 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 */ 78 static FIELD * 79 _formi_create_field(FIELD *, int, int, int, int, int, int); 80 81 82 /* 83 * Set the userptr for the field 84 */ 85 int 86 set_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 99 void * 100 field_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 */ 111 int 112 set_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 */ 124 int 125 field_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 */ 137 int 138 field_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 */ 149 Form_Options 150 field_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 */ 161 int 162 set_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 */ 177 int 178 field_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 */ 189 int 190 field_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 */ 209 int 210 dynamic_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 229 int 230 set_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->opts & O_STATIC) == O_STATIC) && (len > field->cols)) 243 len = field->cols; 244 245 if ((field->buffers[buffer].string = 246 (char *) realloc(field->buffers[buffer].string, len + 1)) == NULL) 247 return E_SYSTEM_ERROR; 248 249 strlcpy(field->buffers[buffer].string, value, len + 1); 250 field->buffers[buffer].length = len; 251 field->buffers[buffer].allocated = len + 1; 252 field->row_count = 1; /* must be at least one row */ 253 254 /* we have to hope the wrap works - if it does not then the 255 buffer is pretty much borked */ 256 status = _formi_wrap_field(field, 0); 257 if (status != E_OK) 258 return status; 259 260 /* redraw the field to reflect the new contents. If the field 261 * is attached.... 262 */ 263 if (field->parent != NULL) 264 _formi_redraw_field(field->parent, field->index); 265 266 return E_OK; 267 } 268 269 /* 270 * Return the requested field buffer to the caller. 271 */ 272 char * 273 field_buffer(FIELD *field, int buffer) 274 { 275 276 if (field == NULL) 277 return NULL; 278 279 if (buffer >= field->nbuf) 280 return NULL; 281 282 return field->buffers[buffer].string; 283 } 284 285 /* 286 * Set the buffer 0 field status. 287 */ 288 int 289 set_field_status(FIELD *field, int status) 290 { 291 292 if (field == NULL) 293 return E_BAD_ARGUMENT; 294 295 if (status != FALSE) 296 field->buf0_status = TRUE; 297 else 298 field->buf0_status = FALSE; 299 300 return E_OK; 301 } 302 303 /* 304 * Return the buffer 0 status flag for the given field. 305 */ 306 int 307 field_status(FIELD *field) 308 { 309 310 if (field == NULL) /* the default buffer 0 never changes :-) */ 311 return FALSE; 312 313 return field->buf0_status; 314 } 315 316 /* 317 * Set the maximum growth for a dynamic field. 318 */ 319 int 320 set_max_field(FIELD *fptr, int max) 321 { 322 FIELD *field = (field == NULL)? &_formi_default_field : fptr; 323 324 if ((field->opts & O_STATIC) == O_STATIC) /* check if field dynamic */ 325 return E_BAD_ARGUMENT; 326 327 if (max < 0) /* negative numbers are bad.... */ 328 return E_BAD_ARGUMENT; 329 330 field->max = max; 331 return E_OK; 332 } 333 334 /* 335 * Set the field foreground character attributes. 336 */ 337 int 338 set_field_fore(FIELD *fptr, chtype attribute) 339 { 340 FIELD *field = (fptr == NULL)? &_formi_default_field : fptr; 341 342 field->fore = attribute; 343 return E_OK; 344 } 345 346 /* 347 * Return the foreground character attribute for the given field. 348 */ 349 chtype 350 field_fore(FIELD *field) 351 { 352 if (field == NULL) 353 return _formi_default_field.fore; 354 else 355 return field->fore; 356 } 357 358 /* 359 * Set the background character attribute for the given field. 360 */ 361 int 362 set_field_back(FIELD *field, chtype attribute) 363 { 364 if (field == NULL) 365 _formi_default_field.back = attribute; 366 else 367 field->back = attribute; 368 369 return E_OK; 370 } 371 372 /* 373 * Set the pad character for the given field. 374 */ 375 int 376 set_field_pad(FIELD *field, int pad) 377 { 378 if (field == NULL) 379 _formi_default_field.pad = pad; 380 else 381 field->pad = pad; 382 383 return E_OK; 384 } 385 386 /* 387 * Return the padding character for the given field. 388 */ 389 int 390 field_pad(FIELD *field) 391 { 392 if (field == NULL) 393 return _formi_default_field.pad; 394 else 395 return field->pad; 396 } 397 398 /* 399 * Set the field initialisation function hook. 400 */ 401 int 402 set_field_init(FORM *form, Form_Hook function) 403 { 404 if (form == NULL) 405 _formi_default_form.field_init = function; 406 else 407 form->field_init = function; 408 409 return E_OK; 410 } 411 412 /* 413 * Return the function hook for the field initialisation. 414 */ 415 Form_Hook 416 field_init(FORM *form) 417 { 418 if (form == NULL) 419 return _formi_default_form.field_init; 420 else 421 return form->field_init; 422 } 423 424 /* 425 * Set the field termination function hook. 426 */ 427 int 428 set_field_term(FORM *form, Form_Hook function) 429 { 430 if (form == NULL) 431 _formi_default_form.field_term = function; 432 else 433 form->field_term = function; 434 435 return E_OK; 436 } 437 438 /* 439 * Return the function hook defined for the field termination. 440 */ 441 Form_Hook 442 field_term(FORM *form) 443 { 444 if (form == NULL) 445 return _formi_default_form.field_term; 446 else 447 return form->field_term; 448 } 449 450 /* 451 * Set the page flag on the given field to indicate it is the start of a 452 * new page. 453 */ 454 int 455 set_new_page(FIELD *fptr, int page) 456 { 457 FIELD *field = (fptr == NULL)? &_formi_default_field : fptr; 458 459 if (field->parent != NULL) /* check if field is connected to a form */ 460 return E_CONNECTED; 461 462 field->page_break = (page != FALSE); 463 return E_OK; 464 } 465 466 /* 467 * Return the page status for the given field. TRUE is returned if the 468 * field is the start of a new page. 469 */ 470 int 471 new_page(FIELD *field) 472 { 473 if (field == NULL) 474 return _formi_default_field.page_break; 475 else 476 return field->page_break; 477 } 478 479 /* 480 * Return the index of the field in the form fields array. 481 */ 482 int 483 field_index(FIELD *field) 484 { 485 if (field == NULL) 486 return -1; 487 488 if (field->parent == NULL) 489 return -1; 490 491 return field->index; 492 } 493 494 /* 495 * Internal function that does most of the work to create a new field. 496 * The new field is initialised from the information in the prototype 497 * field passed. 498 * Returns NULL on error. 499 */ 500 static FIELD * 501 _formi_create_field(FIELD *prototype, int rows, int cols, int frow, 502 int fcol, int nrows, int nbuf) 503 { 504 FIELD *new; 505 506 if ((rows <= 0) || (cols <= 0) || (frow < 0) || (fcol < 0) || 507 (nrows < 0) || (nbuf < 0)) 508 return NULL; 509 510 if ((new = (FIELD *)malloc(sizeof(FIELD))) == NULL) { 511 return NULL; 512 } 513 514 /* copy in the default field info */ 515 bcopy(prototype, new, sizeof(FIELD)); 516 517 new->nbuf = nbuf + 1; 518 new->rows = rows; 519 new->cols = cols; 520 new->form_row = frow; 521 new->form_col = fcol; 522 new->nrows = nrows; 523 new->link = new; 524 return new; 525 } 526 527 /* 528 * Create a new field structure. 529 */ 530 FIELD * 531 new_field(int rows, int cols, int frow, int fcol, int nrows, int nbuf) 532 { 533 FIELD *new; 534 size_t buf_len; 535 int i; 536 537 538 if ((new = _formi_create_field(&_formi_default_field, rows, cols, 539 frow, fcol, nrows, nbuf)) == NULL) 540 return NULL; 541 542 buf_len = (nbuf + 1) * sizeof(FORM_STR); 543 544 if ((new->buffers = (FORM_STR *)malloc(buf_len)) == NULL) { 545 free(new); 546 return NULL; 547 } 548 549 /* Initialise the strings to a zero length string */ 550 for (i = 0; i < nbuf + 1; i++) { 551 if ((new->buffers[i].string = 552 (char *) malloc(sizeof(char))) == NULL) 553 return NULL; 554 new->buffers[i].string[0] = '\0'; 555 new->buffers[i].length = 0; 556 new->buffers[i].allocated = 1; 557 } 558 559 return new; 560 } 561 562 /* 563 * Duplicate the given field, including it's buffers. 564 */ 565 FIELD * 566 dup_field(FIELD *field, int frow, int fcol) 567 { 568 FIELD *new; 569 size_t row_len, buf_len; 570 571 if (field == NULL) 572 return NULL; 573 574 if ((new = _formi_create_field(field, (int) field->rows, 575 (int ) field->cols, 576 frow, fcol, (int) field->nrows, 577 field->nbuf - 1)) == NULL) 578 return NULL; 579 580 row_len = (field->rows + field->nrows + 1) * field->cols; 581 buf_len = (field->nbuf + 1) * row_len * sizeof(FORM_STR); 582 583 if ((new->buffers = (FORM_STR *)malloc(buf_len)) == NULL) { 584 free(new); 585 return NULL; 586 } 587 588 /* copy the buffers from the source field into the new copy */ 589 bcopy(field->buffers, new->buffers, buf_len); 590 591 return new; 592 } 593 594 /* 595 * Create a new field at the specified location by duplicating the given 596 * field. The buffers are shared with the parent field. 597 */ 598 FIELD * 599 link_field(FIELD *field, int frow, int fcol) 600 { 601 FIELD *new; 602 603 if (field == NULL) 604 return NULL; 605 606 if ((new = _formi_create_field(field, (int) field->rows, 607 (int) field->cols, 608 frow, fcol, (int) field->nrows, 609 field->nbuf - 1)) == NULL) 610 return NULL; 611 612 new->link = field->link; 613 field->link = new; 614 615 /* we are done. The buffer pointer was copied during the field 616 creation. */ 617 return new; 618 } 619 620 /* 621 * Release all storage allocated to the field 622 */ 623 int 624 free_field(FIELD *field) 625 { 626 FIELD *flink; 627 628 if (field == NULL) 629 return E_BAD_ARGUMENT; 630 631 if (field->parent != NULL) 632 return E_CONNECTED; 633 634 if (field->link == field) { /* check if field linked */ 635 /* no it is not - release the buffers */ 636 free(field->buffers); 637 } else { 638 /* is linked, traverse the links to find the field referring 639 * to the one to be freed. 640 */ 641 for (flink = field->link; flink != field; flink = flink->link); 642 flink->link = field->link; 643 } 644 645 free(field); 646 return E_OK; 647 } 648 649 650