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