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" /* SVr4.0 1.7 */ 32 33 /*LINTLIBRARY*/ 34 35 #include <sys/types.h> 36 #include "utility.h" 37 38 #define Scrollable(f) ((f)->drows > (f)->rows || \ 39 (f)->dcols > (f)->cols) 40 #define Connected(f) ((f) -> form != (FORM *) 0) 41 #define OnPage(f) ((f) -> page == P((f) -> form)) 42 #define Posted(f) (Status((f) -> form, POSTED)) 43 #define Visible(f) (Opt(f, O_VISIBLE) && OnPage(f)) 44 #define isCurrent(f) ((f) == C((f) -> form)) 45 #define Justified(f) (Just(f) != NO_JUSTIFICATION && \ 46 OneRow(f) && Opt(f, O_STATIC) && \ 47 f->dcols == f->cols) 48 49 /* _data_beg - return ptr to first non-blank char in v[n] (v on failure) */ 50 char * 51 _data_beg(char *v, int n) 52 { 53 char *vend = v + n; 54 while (v < vend && *v == ' ') ++v; 55 return (v == vend ? v - n : v); 56 } 57 58 /* 59 * _data_end - return ptr to char after last 60 * non-blank char in v[n] (v on failure) 61 */ 62 char * 63 _data_end(char *v, int n) 64 { 65 char *vend = v + n; 66 while (vend > v && *(vend - 1) == ' ') --vend; 67 return (vend); 68 } 69 70 /* _whsp_beg - return ptr to first blank in v[n] (v on failure) */ 71 char * 72 _whsp_beg(char *v, int n) 73 { 74 char * vend = v + n; 75 while (v < vend && *v != ' ') ++v; 76 return (v == vend ? v - n : v); 77 } 78 79 /* _whsp_end - return ptr to char after last blank in v[n] (v on failure) */ 80 char * 81 _whsp_end(char *v, int n) 82 { 83 char * vend = v + n; 84 while (vend > v && *(vend - 1) != ' ') --vend; 85 return (vend); 86 } 87 88 /* 89 * _adjust_cursor - adjust cursor based on 90 * offset of v from beginning of field buffer 91 */ 92 void 93 _adjust_cursor(FORM *f, char *v) 94 { 95 int pos = (int) (v - Buf(C(f))); 96 97 Y(f) = pos / Xmax(f); 98 X(f) = pos - Y(f) * Xmax(f); 99 100 if (Y(f) >= Ymax(f)) 101 Y(f) = 0; 102 } 103 104 /* 105 * _buf_to_win - copy buffer to window(trailing 106 * blanks on each line are not copied) 107 */ 108 void 109 _buf_to_win(FIELD *f, WINDOW *w) 110 { 111 char * v = Buf(f); 112 int xmax, ymax, y, n; 113 114 getmaxyx(w, ymax, xmax); 115 116 for (y = 0; y < ymax; ++y) { 117 if ((n = (int) (_data_end(v, xmax) - v)) != 0) { 118 (void) wmove(w, y, 0); 119 (void) waddnstr(w, v, n); 120 } 121 v += xmax; 122 } 123 } 124 125 /* _win_to_buf - copy window to buffer */ 126 void 127 _win_to_buf(WINDOW *w, FIELD *f) 128 { 129 int i; 130 int size = BufSize(f); 131 int pad = Pad(f); 132 char * v = Buf(f); 133 134 (void) wmove(w, 0, 0); 135 (void) winnstr(w, v, size); 136 137 if (pad != ' ') 138 for (i = 0; i < size; ++i, ++v) 139 if (*v == pad) 140 *v = ' '; /* replace pad char with blank */ 141 } 142 143 /* _pos_form_cursor - move to cursor position and sync up cursor */ 144 int 145 _pos_form_cursor(FORM *f) 146 { 147 WINDOW * w = W(f); 148 FIELD * c = C(f); 149 150 if (!w) 151 return (E_SYSTEM_ERROR); 152 153 (void) wmove(w, Y(f), X(f)); 154 155 if (Opt(c, O_PUBLIC)) { 156 if (Scrollable(c)) { 157 int row, col; 158 159 if (OneRow(c)) { 160 row = c->frow; 161 col = c->fcol + X(f) - B(f); 162 } else { 163 row = c -> frow + Y(f) - T(f); 164 col = c -> fcol + X(f); 165 } 166 167 (void) wmove(Sub(f), row, col); 168 wcursyncup(Sub(f)); 169 } else 170 wcursyncup(w); 171 } else { 172 (void) wmove(Sub(f), c -> frow, c -> fcol); 173 wcursyncup(Sub(f)); 174 } 175 return (E_OK); 176 } 177 178 /* _update_current - sync up current field */ 179 int 180 _update_current(FORM *f) 181 { 182 WINDOW * w = W(f); 183 FIELD * c = C(f); 184 185 if (!w) 186 return (E_SYSTEM_ERROR); 187 188 if (Opt(c, O_PUBLIC)) { 189 if (Scrollable(c)) { 190 if (OneRow(c)) { 191 int xmax = B(f) + c->cols; 192 193 if (X(f) < B(f)) 194 B(f) = X(f); 195 else if (X(f) >= xmax) 196 B(f) = X(f) - c->cols + 1; 197 198 (void) copywin(w, Sub(f), 0, B(f), c->frow, 199 c->fcol, c->frow, c->fcol + c->cols - 1, 200 FALSE); 201 202 } else { 203 int ymax = T(f) + c -> rows; 204 int ys, ye; 205 206 if (Y(f) < T(f)) { 207 T(f) = Y(f); 208 Set(c, TOP_CHG); 209 } 210 if (Y(f) >= ymax) { 211 T(f) = Y(f) - c -> rows + 1; 212 Set(c, TOP_CHG); 213 } 214 if (Status(c, TOP_CHG)) { 215 ys = T(f); 216 ye = ys + c -> rows; 217 Clr(c, TOP_CHG); 218 } else { 219 /* intersect changed lines with visible lines */ 220 for (ys = T(f); ys < ymax; ++ys) 221 if (is_linetouched(w, ys)) 222 break; 223 224 for (ye = ys; ye < ymax; ++ye) 225 if (! is_linetouched(w, ye)) 226 break; 227 } 228 if (ye - ys) { 229 (void) copywin(w, Sub(f), ys, 0, 230 c -> frow + ys - T(f), c -> fcol, 231 c -> frow + ye - T(f) - 1, 232 c -> fcol + c -> cols - 1, FALSE); 233 } 234 } 235 wsyncup(Sub(f)); 236 } else 237 wsyncup(w); 238 } 239 (void) untouchwin(w); 240 return (_pos_form_cursor(f)); 241 } 242 243 /* justify - justify field f in window w as given by Just(f) */ 244 static void 245 justify(FIELD *f, WINDOW *w) 246 { 247 char * v = _data_beg(Buf(f), BufSize(f)); 248 char * vend = _data_end(Buf(f), BufSize(f)); 249 int n = (int) (vend - v); 250 int x = 0; 251 252 if (n) { 253 switch (Just(f)) { 254 case JUSTIFY_LEFT: 255 break; 256 case JUSTIFY_CENTER: 257 x = (f -> cols - n) / 2; 258 break; 259 case JUSTIFY_RIGHT: 260 x = f -> cols - n; 261 break; 262 } 263 (void) wmove(w, 0, x); 264 (void) waddnstr(w, v, n); 265 } 266 } 267 268 /* unjustify - left justify field f in window w for editing */ 269 static void 270 unjustify(FIELD *f, WINDOW *w) 271 { 272 char * v = _data_beg(Buf(f), BufSize(f)); 273 char * vend = _data_end(Buf(f), BufSize(f)); 274 int n = (int) (vend - v); 275 276 if (n) { 277 (void) wmove(w, 0, 0); 278 (void) waddnstr(w, v, n); 279 } 280 } 281 282 /* _sync_buffer - sync current field with characters in window */ 283 void 284 _sync_buffer(FORM *f) 285 { 286 if (Status(f, WIN_CHG)) { 287 Clr(f, WIN_CHG); 288 Set(f, BUF_CHG); 289 _win_to_buf(W(f), C(f)); 290 (void) wmove(W(f), Y(f), X(f)); 291 } 292 } 293 294 /* _sync_linked - sync fields linked to field f */ 295 int 296 _sync_linked(FIELD *f) 297 { 298 FIELD * p = f -> link; 299 int err = 0; 300 301 while (p != f) { 302 if (_sync_field(p) != E_OK) 303 ++err; 304 p = p -> link; 305 } 306 return (err ? E_SYSTEM_ERROR : E_OK); 307 } 308 309 /* display_field - display field f */ 310 static int 311 display_field(FIELD *f) 312 { 313 WINDOW * w = derwin(Sub(f -> form), f -> rows, f -> cols, 314 f -> frow, f -> fcol); 315 316 if (!w) 317 return (FALSE); 318 319 wbkgdset(w, Pad(f) | Back(f)); 320 (void) wattrset(w, Fore(f)); 321 (void) werase(w); 322 323 if (Opt(f, O_PUBLIC)) { 324 if (Justified(f)) 325 justify(f, w); 326 else 327 _buf_to_win(f, w); 328 } 329 wsyncup(w); 330 (void) delwin(w); 331 Clr(f, TOP_CHG); 332 return (TRUE); 333 } 334 335 /* erase_field - erase field f */ 336 static int 337 erase_field(FIELD *f) 338 { 339 WINDOW * w = derwin(Sub(f -> form), f -> rows, f -> cols, 340 f -> frow, f -> fcol); 341 342 if (!w) 343 return (FALSE); 344 345 (void) werase(w); 346 wsyncup(w); 347 (void) delwin(w); 348 return (TRUE); 349 } 350 351 /* _sync_field - sync the field after a change to the field buffer */ 352 int 353 _sync_field(FIELD *f) 354 { 355 int v = TRUE; 356 357 if (Connected(f) && Posted(f) && Visible(f)) { 358 if (isCurrent(f)) { 359 FORM * p = f -> form; 360 WINDOW * w = W(p); 361 362 Clr(p, WIN_CHG | BUF_CHG); 363 364 Y(p) = 0; 365 X(p) = 0; 366 T(p) = 0; 367 B(p) = 0; 368 (void) werase(w); 369 370 if (Opt(f, O_PUBLIC) && Justified(f)) 371 unjustify(f, w); 372 else 373 _buf_to_win(f, w); 374 375 Set(f, TOP_CHG); 376 (void) _update_current(p); 377 } else 378 v = display_field(f); 379 } 380 Set(f, USR_CHG); 381 382 return (v ? E_OK : E_SYSTEM_ERROR); 383 } 384 385 /* _sync_attrs - sync the field after a change to a field attribute */ 386 int 387 _sync_attrs(FIELD *f) 388 { 389 int v = TRUE; 390 391 if (Connected(f) && Posted(f) && Visible(f)) { 392 if (isCurrent(f)) { 393 FORM * p = f -> form; 394 WINDOW * w = W(p); 395 396 _sync_buffer(p); 397 398 wbkgdset(w, Pad(f) | Back(f)); 399 (void) wattrset(w, Fore(f)); 400 (void) werase(w); 401 402 if (Opt(f, O_PUBLIC)) { 403 if (Justified(f)) 404 unjustify(f, w); 405 else 406 _buf_to_win(f, w); 407 } else { 408 (void) copywin(w, Sub(p), 0, 0, f -> frow, 409 f -> fcol, f -> rows - 1, f -> cols - 1, 410 FALSE); 411 wsyncup(Sub(p)); 412 _buf_to_win(f, w); 413 } 414 Set(f, TOP_CHG); 415 (void) _update_current(p); 416 } else 417 v = display_field(f); 418 } 419 return (v ? E_OK : E_SYSTEM_ERROR); 420 } 421 422 int 423 _sync_opts(FIELD *f, OPTIONS opts) 424 { 425 int v = TRUE; 426 OPTIONS oldopts = f -> opts; 427 OPTIONS x = opts ^ oldopts; 428 /* x & opt indicates option opt has changed state */ 429 f -> opts = opts; 430 431 if (Connected(f)) { 432 if (isCurrent(f)) { 433 f -> opts = oldopts; 434 return (E_CURRENT); 435 } 436 if (Posted(f) && OnPage(f)) { 437 if (x & O_VISIBLE) { 438 if (Opt(f, O_VISIBLE)) 439 v = display_field(f); 440 else 441 v = erase_field(f); 442 } else if (x & O_PUBLIC) { 443 if (Opt(f, O_VISIBLE)) 444 v = display_field(f); 445 } 446 } 447 } 448 449 if (x & O_STATIC) { 450 BOOLEAN onerow = OneRow(f); 451 int max = f->maxgrow; 452 453 if (Opt(f, O_STATIC)) { /* growth being turned off */ 454 Clr(f, GROWABLE); 455 456 if (onerow && f->cols == f->dcols && 457 Just(f) != NO_JUSTIFICATION && Posted(f) && 458 OnPage(f) && Opt(f, O_VISIBLE)) { 459 (void) display_field(f); 460 } 461 } else if (!max || (onerow && f->dcols < max) || 462 (!onerow && f->drows < max)) { 463 Set(f, GROWABLE); 464 465 if (onerow && Just(f) != NO_JUSTIFICATION && 466 Posted(f) && OnPage(f) && Opt(f, O_VISIBLE)) { 467 (void) display_field(f); 468 } 469 } 470 } 471 472 return (v ? E_OK : E_SYSTEM_ERROR); 473 } 474 475 /* _validate - validate current field */ 476 int 477 _validate(FORM *f) 478 { 479 FIELD * c = C(f); 480 481 _sync_buffer(f); 482 483 if (Status(f, BUF_CHG) || !Opt(c, O_PASSOK)) { 484 if (CheckField(c)) { 485 Clr(f, BUF_CHG); 486 Set(c, USR_CHG); 487 (void) _sync_linked(c); 488 } else 489 return (FALSE); 490 } 491 return (TRUE); 492 } 493 494 /* 495 * _set_current_field - change current field on form f to given field. 496 * POSTED flag is set unless this is called from post_form(). 497 */ 498 int 499 _set_current_field(FORM *f, FIELD *field) 500 { 501 WINDOW * w = W(f); 502 FIELD * c = C(f); 503 504 if (c != field || ! Status(f, POSTED)) { 505 if (w) { 506 if (Visible(c)) { 507 (void) _update_current(f); 508 509 if (Opt(c, O_PUBLIC)) { 510 if (Scrollable(c)) { 511 if (T(f) == 0) 512 Clr(c, TOP_CHG); 513 else 514 Set(c, TOP_CHG); 515 } else if (Justified(c)) { 516 (void) werase(w); 517 justify(c, w); 518 wsyncup(w); 519 } 520 } 521 } 522 (void) delwin(w); 523 } 524 c = field; 525 526 if (!Opt(c, O_PUBLIC) || Scrollable(c)) 527 w = newwin(c -> drows, c -> dcols, 0, 0); 528 else 529 w = derwin(Sub(f), c -> rows, c -> cols, c -> frow, 530 c -> fcol); 531 532 if (!w) 533 return (E_SYSTEM_ERROR); 534 535 C(f) = c; 536 W(f) = w; 537 wbkgdset(w, Pad(c) | Back(c)); 538 (void) wattrset(w, Fore(c)); 539 540 if (!Opt(c, O_PUBLIC) || Scrollable(c)) { 541 (void) werase(w); 542 _buf_to_win(c, w); 543 } else if (Justified(c)) { 544 (void) werase(w); 545 unjustify(c, w); 546 wsyncup(w); 547 } 548 (void) untouchwin(w); 549 Clr(f, WIN_CHG | BUF_CHG); 550 } 551 Y(f) = 0; 552 X(f) = 0; 553 T(f) = 0; 554 B(f) = 0; 555 return (E_OK); 556 } 557 558 /* 559 * _set_form_page - display given page and set current field to c. 560 * if c is null, then set current field to first field on page. 561 * POSTED flag is set unless this is called from post_form(). 562 */ 563 int 564 _set_form_page(FORM *f, int page, FIELD *c) 565 { 566 if (P(f) != page || ! Status(f, POSTED)) { 567 FIELD * x = f -> field [Smin(f, page)]; 568 FIELD * p = x; 569 570 (void) werase(Sub(f)); 571 P(f) = page; 572 573 do { 574 if (Opt(p, O_VISIBLE)) 575 if (!display_field(p)) 576 return (E_SYSTEM_ERROR); 577 p = p -> snext; 578 579 } while (p != x); 580 581 return (c ? _set_current_field(f, c) : _first_field(f)); 582 } 583 return (E_OK); 584 } 585