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 *
_data_beg(char * v,int n)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 *
_data_end(char * v,int n)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 *
_whsp_beg(char * v,int n)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 *
_whsp_end(char * v,int n)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
_adjust_cursor(FORM * f,char * v)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
_buf_to_win(FIELD * f,WINDOW * w)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
_win_to_buf(WINDOW * w,FIELD * f)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
_pos_form_cursor(FORM * f)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
_update_current(FORM * f)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
justify(FIELD * f,WINDOW * w)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
unjustify(FIELD * f,WINDOW * w)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
_sync_buffer(FORM * f)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
_sync_linked(FIELD * f)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
display_field(FIELD * f)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
erase_field(FIELD * f)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
_sync_field(FIELD * f)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
_sync_attrs(FIELD * f)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
_sync_opts(FIELD * f,OPTIONS opts)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
_validate(FORM * f)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
_set_current_field(FORM * f,FIELD * field)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
_set_form_page(FORM * f,int page,FIELD * c)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