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