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