1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* Copyright (c) 1988 AT&T */ 23 /* All Rights Reserved */ 24 25 26 /* 27 * Copyright (c) 1997, by Sun Microsystems, Inc. 28 * All rights reserved. 29 */ 30 31 /*LINTLIBRARY*/ 32 33 #include <sys/types.h> 34 #include <stdlib.h> 35 #include "utility.h" 36 37 #define AT_BOTTOM(f) (Y(f) == Ymax(f) - 1) /* last line */ 38 #define AT_END(f) (Y(f) == Ymax(f) - 1 && X(f) == Xmax(f) - 1) 39 /* last char */ 40 #define AT_BEGINNING(f) (Y(f) == 0 && X(f) == 0) /* first char */ 41 42 static int 43 room_for_line(FORM *f) 44 { 45 char *v; 46 47 _sync_buffer(f); 48 v = LineBuf(C(f), Ymax(f) - 1); 49 return (v == _data_end(v, Xmax(f))); /* check for empty line */ 50 } 51 52 static int 53 room_for_char(FORM *f) 54 { 55 WINDOW * w = W(f); 56 int c; 57 58 (void) wmove(w, Y(f), Xmax(f) - 1); 59 c = (int)(winch(w) & A_CHARTEXT); 60 (void) wmove(w, Y(f), X(f)); 61 return (c == Pad(C(f))); /* check for empty char */ 62 } 63 64 static int 65 extra_padding(char *str, int nstr) /* used for word wrapping */ 66 { 67 int c = *(str + nstr - 1); 68 69 if (c == '"' || c == '\'') 70 c = *(str + nstr - 2); 71 72 return ((c == '.' || c == '?' || c == '!' || c == ':') ? 2 : 1); 73 74 } 75 76 BOOLEAN 77 _grow_field(FIELD *c, int chunks) 78 { 79 /* This function handles the growth of dymanically growable fields */ 80 /* Returns TRUE if successful, FALSE otherwise */ 81 82 FORM *f = c->form; 83 WINDOW *w = W(f); 84 BOOLEAN current = Status(f, POSTED) && c == C(f); 85 char *old_buf; 86 char *new_buf; 87 char *save; 88 int old_len = BufSize(c); 89 int grow; 90 int lcv; 91 int max = c->maxgrow; 92 int i; 93 94 if (current && Status(f, WIN_CHG)) { 95 _win_to_buf(w, c); 96 Clr(f, WIN_CHG); 97 Set(f, BUF_CHG); 98 } 99 100 if (OneRow(c)) { 101 grow = chunks * c->cols; 102 103 if (max) 104 grow = MIN(max - c->dcols, grow); 105 106 c->dcols += grow; 107 108 if (c->dcols == max) 109 Clr(c, GROWABLE); 110 } else { 111 grow = chunks * (c->rows + c->nrow); 112 113 if (max) 114 grow = MIN(max - c->drows, grow); 115 116 c->drows += grow; 117 grow *= c->cols; 118 119 if (c->drows == max) 120 Clr(c, GROWABLE); 121 } 122 123 save = old_buf = Buf(c); 124 new_buf = Buf(c) = malloc(TotalBuf(c)); 125 126 if (!new_buf) 127 return (FALSE); 128 129 lcv = c->nbuf + 1; 130 131 for (i = 0; i < lcv; i++) { 132 (void) memcpy(new_buf, old_buf, old_len); 133 (void) memset(new_buf + old_len, ' ', grow); 134 old_buf += old_len + 1; 135 new_buf += old_len + grow; 136 *new_buf++ = '\0'; 137 } 138 139 free(save); /* delete old buffer */ 140 141 if (current) { 142 (void) delwin(w); 143 W(f) = w = newwin(c->drows, c->dcols, 0, 0); 144 145 if (!w) 146 return (FALSE); 147 148 wbkgdset(w, Pad(c) | Back(c)); 149 (void) wattrset(w, Fore(c)); 150 (void) werase(w); 151 _buf_to_win(c, w); 152 (void) untouchwin(w); 153 (void) wmove(w, Y(f), X(f)); 154 } 155 156 if (c->link != c) { 157 FIELD *p = c->link; 158 159 while (p != c) { 160 Buf(p) = Buf(c); 161 p->drows = c->drows; 162 p->dcols = c->dcols; 163 /* _sync_field(p) */ 164 p = p->link; 165 } 166 } 167 168 return (TRUE); 169 } 170 171 static int 172 insert_str(FORM *f, int y, int off, int nstr) /* used for word wrapping */ 173 { 174 WINDOW *w = W(f); 175 FIELD *c = C(f); 176 char *vbeg = LineBuf(c, y); 177 char *v = _data_end(vbeg, Xmax(f)); 178 int x = (int)(v - vbeg); 179 int n = Xmax(f) - x; 180 int pad = extra_padding(Buf(c) + off, nstr); 181 int siz = nstr + 1 + pad; 182 int ret = E_REQUEST_DENIED; 183 184 if (n >= siz) { /* check for fit on this line */ 185 (void) wmove(w, y, 0); 186 (void) winsnstr(w, Buf(c) + off, nstr); 187 (void) wmove(w, y, nstr); 188 (void) winsnstr(w, " ", pad); 189 } else { /* wrap */ 190 if (y == Ymax(f) - 1 && Status(c, GROWABLE)) { 191 if (!_grow_field(c, 1)) 192 return (E_SYSTEM_ERROR); 193 194 vbeg = LineBuf(c, y); /* grow changes buffer */ 195 w = W(f); /* grow changes window */ 196 } 197 198 v = _data_beg(vbeg + Xmax(f) - siz, siz); 199 v = _whsp_end(vbeg, (int)(v - vbeg)); 200 x = (int)(v - vbeg); 201 n = Xmax(f) - x - n; 202 203 if (y < Ymax(f) - 1 && (ret = 204 insert_str(f, y+1, (int)(v - Buf(c)), n)) == E_OK) { 205 (void) wmove(w, y, x); 206 (void) wclrtoeol(w); 207 (void) wmove(w, y, 0); 208 (void) winsnstr(w, Buf(c) + off, nstr); 209 (void) wmove(w, y, nstr); 210 (void) winsnstr(w, " ", pad); 211 } else 212 return (ret); /* no room for wrap */ 213 } 214 return (E_OK); 215 } 216 217 static int 218 wrap_ok(FORM *f) /* used for word wrapping */ 219 { 220 /* 221 * when this routine is called a char has already been added/inserted 222 * on the screen at Y(f), X(f). this routine checks to see if the current 223 * line needs wrapping and if so attempts the wrap. if unsuccessful 224 * it deletes the char at Y(f), X(f) and returns FALSE. 225 */ 226 FIELD *c = C(f); 227 BOOLEAN at_bottom = AT_BOTTOM(f); 228 int ret = E_REQUEST_DENIED; 229 230 if (Opt(c, O_WRAP) && !OneRow(c) && !room_for_char(f) && 231 (!at_bottom || Status(c, GROWABLE))) { 232 WINDOW *w; 233 char *vbeg; 234 char *v; 235 int x, n; 236 237 if (at_bottom && !_grow_field(c, 1)) 238 return (E_SYSTEM_ERROR); 239 240 vbeg = LineBuf(c, Y(f)); 241 w = W(f); 242 243 _win_to_buf(w, c); /* sync buffer without changing flags */ 244 245 v = _whsp_end(vbeg, Xmax(f)); 246 x = (int)(v - vbeg); 247 n = Xmax(f) - x; 248 249 if (x && (ret = insert_str(f, Y(f)+1, (int)(v - Buf(c)), n)) == 250 E_OK) { 251 w = W(f); /* window may change in insert_str */ 252 (void) wmove(w, Y(f), x); 253 (void) wclrtoeol(w); 254 255 if (X(f) >= x) { 256 ++Y(f); 257 X(f) = X(f) - x; 258 } 259 } else { /* error condition */ 260 if (ret == E_SYSTEM_ERROR) 261 return (E_SYSTEM_ERROR); 262 263 (void) wmove(w, Y(f), X(f)); 264 (void) wdelch(w); /* delete the char */ 265 _win_to_buf(w, c); /* restore buffer */ 266 return (E_REQUEST_DENIED); 267 } 268 } 269 return (E_OK); 270 } 271 272 int 273 _new_line(FORM *f) 274 { 275 /* 276 * overloaded operation 277 * 278 * if at beginning of field 279 * move to next field 280 * 281 * else if in OVERLAY mode 282 * if on last line of field 283 * clear to eol and move to next field 284 * else 285 * clear to eol and move to beginning of next line 286 * 287 * else if in INSERT mode 288 * if on last line of field 289 * move to next field 290 * else 291 * move text from cursor to eol to new line 292 */ 293 BOOLEAN at_bottom = AT_BOTTOM(f); 294 FIELD * c = C(f); 295 296 if (Opt(f, O_NL_OVERLOAD) && AT_BEGINNING(f)) 297 return (_field_navigation(_next_field, f)); 298 299 if (!Opt(c, O_EDIT)) 300 return (E_REQUEST_DENIED); 301 302 if (Status(f, OVERLAY)) { /* OVERLAY mode */ 303 if (at_bottom && (!Status(c, GROWABLE) || OneRow(c))) { 304 if (Opt(f, O_NL_OVERLOAD)) { 305 (void) wclrtoeol(W(f)); 306 Set(f, WIN_CHG); 307 return (_field_navigation(_next_field, f)); 308 } else 309 return (E_REQUEST_DENIED); 310 } 311 312 if (at_bottom && !_grow_field(c, 1)) 313 return (E_SYSTEM_ERROR); 314 315 (void) wclrtoeol(W(f)); 316 ++Y(f); X(f) = 0; 317 } else { /* INSERT mode */ 318 BOOLEAN room; 319 320 if (at_bottom && (!Status(c, GROWABLE) || OneRow(c))) { 321 if (Opt(f, O_NL_OVERLOAD)) 322 return (_field_navigation(_next_field, f)); 323 else 324 return (E_REQUEST_DENIED); 325 } 326 327 room = !at_bottom && room_for_line(f); 328 329 if (room || Status(c, GROWABLE)) { 330 WINDOW *w; 331 char *v; 332 char *vend; 333 334 if (!room && !_grow_field(c, 1)) 335 return (E_SYSTEM_ERROR); 336 337 w = W(f); 338 v = LineBuf(c, Y(f)) + X(f); 339 vend = _data_end(v, Xmax(f) - X(f)); 340 341 (void) wclrtoeol(w); 342 ++Y(f); X(f) = 0; 343 (void) wmove(w, Y(f), X(f)); 344 (void) winsertln(w); 345 (void) waddnstr(w, v, (int)(vend - v)); 346 } else 347 return (E_REQUEST_DENIED); 348 } 349 Set(f, WIN_CHG); 350 return (E_OK); 351 } 352 353 /* _ins_char - insert blank char with error on overflow */ 354 int 355 _ins_char(FORM *f) 356 { 357 FIELD *c = C(f); 358 BOOLEAN room = room_for_char(f); 359 360 if (CheckChar(c, ' ') && (room || (OneRow(c) && 361 Status(c, GROWABLE)))) { 362 if (!room && !_grow_field(c, 1)) 363 return (E_SYSTEM_ERROR); 364 365 (void) winsch(W(f), ' '); 366 367 return (wrap_ok(f)); 368 } 369 return (E_REQUEST_DENIED); 370 } 371 372 /* _ins_line - insert blank line with error on overflow */ 373 int 374 _ins_line(FORM *f) 375 { 376 BOOLEAN room = !AT_BOTTOM(f) && room_for_line(f); 377 FIELD *c = C(f); 378 379 if (CheckChar(c, ' ') && !OneRow(c) && (room || Status(c, GROWABLE))) { 380 if (!room && !_grow_field(c, 1)) 381 return (E_SYSTEM_ERROR); 382 383 X(f) = 0; 384 (void) winsertln(W(f)); 385 return (E_OK); 386 } 387 return (E_REQUEST_DENIED); 388 } 389 390 /* _del_char - delete char at cursor */ 391 int 392 _del_char(FORM *f) 393 { 394 (void) wdelch(W(f)); 395 return (E_OK); 396 } 397 398 int 399 _del_prev(FORM *f) 400 { 401 /* 402 * overloaded operation 403 * 404 * if at beginning of field 405 * move to previous field 406 * 407 * else if in OVERLAY mode 408 * if at beginning of line 409 * error 410 * else 411 * delete previous char 412 * 413 * else if in INSERT mode 414 * if at beginning of line 415 * if current line can fit on preceding 416 * join current line with preceding line 417 * else 418 * error 419 * else 420 * delete previous char 421 */ 422 WINDOW * w = W(f); 423 FIELD * c = C(f); 424 425 if (AT_BEGINNING(f)) { 426 if (Opt(f, O_BS_OVERLOAD)) 427 return (_field_navigation(_prev_field, f)); 428 else 429 return (E_REQUEST_DENIED); 430 } 431 if (!Opt(c, O_EDIT)) 432 return (E_REQUEST_DENIED); 433 434 if (--X(f) < 0) { 435 ++X(f); 436 437 if (Status(f, OVERLAY)) /* OVERLAY mode */ 438 return (E_REQUEST_DENIED); 439 else { /* INSERT mode */ 440 char *p = LineBuf(c, Y(f) - 1); 441 char *v = LineBuf(c, Y(f)); 442 char *pend; 443 char *vend; 444 445 _sync_buffer(f); 446 pend = _data_end(p, Xmax(f)); 447 vend = _data_end(v, Xmax(f)); 448 449 if ((vend - v) > (Xmax(f) - (pend - p))) 450 return (E_REQUEST_DENIED); 451 else { 452 (void) wdeleteln(w); 453 _adjust_cursor(f, pend); 454 (void) wmove(w, Y(f), X(f)); 455 (void) waddnstr(w, v, (int)(vend - v)); 456 } 457 } 458 } else { 459 (void) wmove(w, Y(f), X(f)); 460 (void) wdelch(w); 461 } 462 Set(f, WIN_CHG); 463 return (E_OK); 464 } 465 466 /* _del_line - delete current line */ 467 int 468 _del_line(FORM *f) 469 { 470 X(f) = 0; 471 (void) wdeleteln(W(f)); 472 return (E_OK); 473 } 474 475 /* _del_word - delete word under cursor plus trailing blanks */ 476 int 477 _del_word(FORM *f) 478 { 479 FIELD *c = C(f); 480 WINDOW *w = W(f); 481 char *y = LineBuf(c, Y(f)); 482 char *t = y + Xmax(f); 483 char *v = y + X(f); 484 char *x = v; 485 486 _sync_buffer(f); 487 488 if (*v == ' ') 489 return (E_REQUEST_DENIED); 490 491 _adjust_cursor(f, _whsp_end(y, X(f))); 492 (void) wmove(w, Y(f), X(f)); 493 (void) wclrtoeol(w); 494 495 v = _whsp_beg(v, (int)(t - v)); 496 v = _data_beg(v, (int)(t - v)); 497 498 if (v != x && *v != ' ') 499 (void) waddnstr(w, v, (int)(_data_end(v, (int)(t - v)) - v)); 500 501 return (E_OK); 502 } 503 504 /* _clr_eol - clear to end of line */ 505 int 506 _clr_eol(FORM *f) 507 { 508 (void) wclrtoeol(W(f)); 509 return (E_OK); 510 } 511 512 /* _clr_eof - clear to end of field */ 513 int 514 _clr_eof(FORM *f) 515 { 516 (void) wclrtobot(W(f)); 517 return (E_OK); 518 } 519 520 /* _clr_field - clear entire field */ 521 int 522 _clr_field(FORM *f) 523 { 524 X(f) = 0; Y(f) = 0; 525 (void) werase(W(f)); 526 return (E_OK); 527 } 528 529 /* _ovl_mode - go into overlay mode */ 530 int 531 _ovl_mode(FORM *f) 532 { 533 Set(f, OVERLAY); 534 return (E_OK); 535 } 536 537 /* _ins_mode - go into insert mode */ 538 int 539 _ins_mode(FORM *f) 540 { 541 Clr(f, OVERLAY); 542 return (E_OK); 543 } 544 545 /* _validation - apply validation function associated with field type */ 546 int 547 _validation(FORM *f) 548 { 549 return (_validate(f) ? E_OK : E_INVALID_FIELD); 550 } 551 552 /* _next_choice - apply next choice function associated with field type */ 553 int 554 _next_choice(FORM *f) 555 { 556 _sync_buffer(f); 557 return (NextChoice(C(f)) ? E_OK : E_REQUEST_DENIED); 558 } 559 560 /* _prev_choice - apply previous choice function associated with field type */ 561 int 562 _prev_choice(FORM *f) 563 { 564 _sync_buffer(f); 565 return (PrevChoice(C(f)) ? E_OK : E_REQUEST_DENIED); 566 } 567 568 /* 569 * _data_entry - enter printable ascii char ch 570 * in current field at cursor position 571 */ 572 int 573 _data_entry(FORM *f, int ch) 574 { 575 FIELD * c = C(f); /* current field */ 576 WINDOW * w = W(f); /* field window */ 577 BOOLEAN at_end; 578 int ret; 579 580 if (!Opt(c, O_EDIT)) 581 return (E_REQUEST_DENIED); 582 583 if (AT_BEGINNING(f) && Opt(c, O_BLANK) && ! Status(f, BUF_CHG) && 584 !Status(f, WIN_CHG)) 585 (void) werase(w); 586 587 if (Status(f, OVERLAY)) /* OVERLAY mode */ 588 (void) waddch(w, (chtype) ch); 589 else { /* INSERT mode */ 590 BOOLEAN room = room_for_char(f); 591 592 if (room || (OneRow(c) && Status(c, GROWABLE))) { 593 if (!room && !_grow_field(c, 1)) 594 return (E_SYSTEM_ERROR); 595 596 (void) winsch(w, (chtype) ch); 597 } else 598 return (E_REQUEST_DENIED); 599 } 600 601 if ((ret = wrap_ok(f)) != E_OK) 602 return (ret); 603 604 Set(f, WIN_CHG); 605 606 at_end = AT_END(f); 607 608 if (at_end && !Status(c, GROWABLE) && Opt(c, O_AUTOSKIP)) 609 return (_field_navigation(_next_field, f)); 610 611 if (at_end && Status(c, GROWABLE) && !_grow_field(c, 1)) 612 return (E_SYSTEM_ERROR); 613 614 (void) _next_char(f); 615 return (E_OK); 616 } 617