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