2N/A/*
2N/A * CDDL HEADER START
2N/A *
2N/A * The contents of this file are subject to the terms of the
2N/A * Common Development and Distribution License, Version 1.0 only
2N/A * (the "License"). You may not use this file except in compliance
2N/A * with the License.
2N/A *
2N/A * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
2N/A * or http://www.opensolaris.org/os/licensing.
2N/A * See the License for the specific language governing permissions
2N/A * and limitations under the License.
2N/A *
2N/A * When distributing Covered Code, include this CDDL HEADER in each
2N/A * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
2N/A * If applicable, add the following below this CDDL HEADER, with the
2N/A * fields enclosed by brackets "[]" replaced with your own identifying
2N/A * information: Portions Copyright [yyyy] [name of copyright owner]
2N/A *
2N/A * CDDL HEADER END
2N/A */
2N/A/* Copyright (c) 1988 AT&T */
2N/A/* All Rights Reserved */
2N/A
2N/A
2N/A/*
2N/A * Copyright (c) 1997, by Sun Microsystems, Inc.
2N/A * All rights reserved.
2N/A */
2N/A
2N/A#pragma ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.7 */
2N/A
2N/A/*LINTLIBRARY*/
2N/A
2N/A#include <sys/types.h>
2N/A#include "utility.h"
2N/A
2N/A#define Scrollable(f) ((f)->drows > (f)->rows || \
2N/A (f)->dcols > (f)->cols)
2N/A#define Connected(f) ((f) -> form != (FORM *) 0)
2N/A#define OnPage(f) ((f) -> page == P((f) -> form))
2N/A#define Posted(f) (Status((f) -> form, POSTED))
2N/A#define Visible(f) (Opt(f, O_VISIBLE) && OnPage(f))
2N/A#define isCurrent(f) ((f) == C((f) -> form))
2N/A#define Justified(f) (Just(f) != NO_JUSTIFICATION && \
2N/A OneRow(f) && Opt(f, O_STATIC) && \
2N/A f->dcols == f->cols)
2N/A
2N/A/* _data_beg - return ptr to first non-blank char in v[n] (v on failure) */
2N/Achar *
2N/A_data_beg(char *v, int n)
2N/A{
2N/A char *vend = v + n;
2N/A while (v < vend && *v == ' ') ++v;
2N/A return (v == vend ? v - n : v);
2N/A}
2N/A
2N/A/*
2N/A * _data_end - return ptr to char after last
2N/A * non-blank char in v[n] (v on failure)
2N/A */
2N/Achar *
2N/A_data_end(char *v, int n)
2N/A{
2N/A char *vend = v + n;
2N/A while (vend > v && *(vend - 1) == ' ') --vend;
2N/A return (vend);
2N/A}
2N/A
2N/A/* _whsp_beg - return ptr to first blank in v[n] (v on failure) */
2N/Achar *
2N/A_whsp_beg(char *v, int n)
2N/A{
2N/A char * vend = v + n;
2N/A while (v < vend && *v != ' ') ++v;
2N/A return (v == vend ? v - n : v);
2N/A}
2N/A
2N/A/* _whsp_end - return ptr to char after last blank in v[n] (v on failure) */
2N/Achar *
2N/A_whsp_end(char *v, int n)
2N/A{
2N/A char * vend = v + n;
2N/A while (vend > v && *(vend - 1) != ' ') --vend;
2N/A return (vend);
2N/A}
2N/A
2N/A/*
2N/A * _adjust_cursor - adjust cursor based on
2N/A * offset of v from beginning of field buffer
2N/A */
2N/Avoid
2N/A_adjust_cursor(FORM *f, char *v)
2N/A{
2N/A int pos = (int) (v - Buf(C(f)));
2N/A
2N/A Y(f) = pos / Xmax(f);
2N/A X(f) = pos - Y(f) * Xmax(f);
2N/A
2N/A if (Y(f) >= Ymax(f))
2N/A Y(f) = 0;
2N/A}
2N/A
2N/A/*
2N/A * _buf_to_win - copy buffer to window(trailing
2N/A * blanks on each line are not copied)
2N/A */
2N/Avoid
2N/A_buf_to_win(FIELD *f, WINDOW *w)
2N/A{
2N/A char * v = Buf(f);
2N/A int xmax, ymax, y, n;
2N/A
2N/A getmaxyx(w, ymax, xmax);
2N/A
2N/A for (y = 0; y < ymax; ++y) {
2N/A if ((n = (int) (_data_end(v, xmax) - v)) != 0) {
2N/A (void) wmove(w, y, 0);
2N/A (void) waddnstr(w, v, n);
2N/A }
2N/A v += xmax;
2N/A }
2N/A}
2N/A
2N/A/* _win_to_buf - copy window to buffer */
2N/Avoid
2N/A_win_to_buf(WINDOW *w, FIELD *f)
2N/A{
2N/A int i;
2N/A int size = BufSize(f);
2N/A int pad = Pad(f);
2N/A char * v = Buf(f);
2N/A
2N/A (void) wmove(w, 0, 0);
2N/A (void) winnstr(w, v, size);
2N/A
2N/A if (pad != ' ')
2N/A for (i = 0; i < size; ++i, ++v)
2N/A if (*v == pad)
2N/A *v = ' '; /* replace pad char with blank */
2N/A}
2N/A
2N/A/* _pos_form_cursor - move to cursor position and sync up cursor */
2N/Aint
2N/A_pos_form_cursor(FORM *f)
2N/A{
2N/A WINDOW * w = W(f);
2N/A FIELD * c = C(f);
2N/A
2N/A if (!w)
2N/A return (E_SYSTEM_ERROR);
2N/A
2N/A (void) wmove(w, Y(f), X(f));
2N/A
2N/A if (Opt(c, O_PUBLIC)) {
2N/A if (Scrollable(c)) {
2N/A int row, col;
2N/A
2N/A if (OneRow(c)) {
2N/A row = c->frow;
2N/A col = c->fcol + X(f) - B(f);
2N/A } else {
2N/A row = c -> frow + Y(f) - T(f);
2N/A col = c -> fcol + X(f);
2N/A }
2N/A
2N/A (void) wmove(Sub(f), row, col);
2N/A wcursyncup(Sub(f));
2N/A } else
2N/A wcursyncup(w);
2N/A } else {
2N/A (void) wmove(Sub(f), c -> frow, c -> fcol);
2N/A wcursyncup(Sub(f));
2N/A }
2N/A return (E_OK);
2N/A}
2N/A
2N/A/* _update_current - sync up current field */
2N/Aint
2N/A_update_current(FORM *f)
2N/A{
2N/A WINDOW * w = W(f);
2N/A FIELD * c = C(f);
2N/A
2N/A if (!w)
2N/A return (E_SYSTEM_ERROR);
2N/A
2N/A if (Opt(c, O_PUBLIC)) {
2N/A if (Scrollable(c)) {
2N/A if (OneRow(c)) {
2N/A int xmax = B(f) + c->cols;
2N/A
2N/A if (X(f) < B(f))
2N/A B(f) = X(f);
2N/A else if (X(f) >= xmax)
2N/A B(f) = X(f) - c->cols + 1;
2N/A
2N/A (void) copywin(w, Sub(f), 0, B(f), c->frow,
2N/A c->fcol, c->frow, c->fcol + c->cols - 1,
2N/A FALSE);
2N/A
2N/A } else {
2N/A int ymax = T(f) + c -> rows;
2N/A int ys, ye;
2N/A
2N/A if (Y(f) < T(f)) {
2N/A T(f) = Y(f);
2N/A Set(c, TOP_CHG);
2N/A }
2N/A if (Y(f) >= ymax) {
2N/A T(f) = Y(f) - c -> rows + 1;
2N/A Set(c, TOP_CHG);
2N/A }
2N/A if (Status(c, TOP_CHG)) {
2N/A ys = T(f);
2N/A ye = ys + c -> rows;
2N/A Clr(c, TOP_CHG);
2N/A } else {
2N/A /* intersect changed lines with visible lines */
2N/A for (ys = T(f); ys < ymax; ++ys)
2N/A if (is_linetouched(w, ys))
2N/A break;
2N/A
2N/A for (ye = ys; ye < ymax; ++ye)
2N/A if (! is_linetouched(w, ye))
2N/A break;
2N/A }
2N/A if (ye - ys) {
2N/A (void) copywin(w, Sub(f), ys, 0,
2N/A c -> frow + ys - T(f), c -> fcol,
2N/A c -> frow + ye - T(f) - 1,
2N/A c -> fcol + c -> cols - 1, FALSE);
2N/A }
2N/A }
2N/A wsyncup(Sub(f));
2N/A } else
2N/A wsyncup(w);
2N/A }
2N/A (void) untouchwin(w);
2N/A return (_pos_form_cursor(f));
2N/A}
2N/A
2N/A/* justify - justify field f in window w as given by Just(f) */
2N/Astatic void
2N/Ajustify(FIELD *f, WINDOW *w)
2N/A{
2N/A char * v = _data_beg(Buf(f), BufSize(f));
2N/A char * vend = _data_end(Buf(f), BufSize(f));
2N/A int n = (int) (vend - v);
2N/A int x = 0;
2N/A
2N/A if (n) {
2N/A switch (Just(f)) {
2N/A case JUSTIFY_LEFT:
2N/A break;
2N/A case JUSTIFY_CENTER:
2N/A x = (f -> cols - n) / 2;
2N/A break;
2N/A case JUSTIFY_RIGHT:
2N/A x = f -> cols - n;
2N/A break;
2N/A }
2N/A (void) wmove(w, 0, x);
2N/A (void) waddnstr(w, v, n);
2N/A }
2N/A}
2N/A
2N/A/* unjustify - left justify field f in window w for editing */
2N/Astatic void
2N/Aunjustify(FIELD *f, WINDOW *w)
2N/A{
2N/A char * v = _data_beg(Buf(f), BufSize(f));
2N/A char * vend = _data_end(Buf(f), BufSize(f));
2N/A int n = (int) (vend - v);
2N/A
2N/A if (n) {
2N/A (void) wmove(w, 0, 0);
2N/A (void) waddnstr(w, v, n);
2N/A }
2N/A}
2N/A
2N/A/* _sync_buffer - sync current field with characters in window */
2N/Avoid
2N/A_sync_buffer(FORM *f)
2N/A{
2N/A if (Status(f, WIN_CHG)) {
2N/A Clr(f, WIN_CHG);
2N/A Set(f, BUF_CHG);
2N/A _win_to_buf(W(f), C(f));
2N/A (void) wmove(W(f), Y(f), X(f));
2N/A }
2N/A}
2N/A
2N/A/* _sync_linked - sync fields linked to field f */
2N/Aint
2N/A_sync_linked(FIELD *f)
2N/A{
2N/A FIELD * p = f -> link;
2N/A int err = 0;
2N/A
2N/A while (p != f) {
2N/A if (_sync_field(p) != E_OK)
2N/A ++err;
2N/A p = p -> link;
2N/A }
2N/A return (err ? E_SYSTEM_ERROR : E_OK);
2N/A}
2N/A
2N/A/* display_field - display field f */
2N/Astatic int
2N/Adisplay_field(FIELD *f)
2N/A{
2N/A WINDOW * w = derwin(Sub(f -> form), f -> rows, f -> cols,
2N/A f -> frow, f -> fcol);
2N/A
2N/A if (!w)
2N/A return (FALSE);
2N/A
2N/A wbkgdset(w, Pad(f) | Back(f));
2N/A (void) wattrset(w, Fore(f));
2N/A (void) werase(w);
2N/A
2N/A if (Opt(f, O_PUBLIC)) {
2N/A if (Justified(f))
2N/A justify(f, w);
2N/A else
2N/A _buf_to_win(f, w);
2N/A }
2N/A wsyncup(w);
2N/A (void) delwin(w);
2N/A Clr(f, TOP_CHG);
2N/A return (TRUE);
2N/A}
2N/A
2N/A/* erase_field - erase field f */
2N/Astatic int
2N/Aerase_field(FIELD *f)
2N/A{
2N/A WINDOW * w = derwin(Sub(f -> form), f -> rows, f -> cols,
2N/A f -> frow, f -> fcol);
2N/A
2N/A if (!w)
2N/A return (FALSE);
2N/A
2N/A (void) werase(w);
2N/A wsyncup(w);
2N/A (void) delwin(w);
2N/A return (TRUE);
2N/A}
2N/A
2N/A/* _sync_field - sync the field after a change to the field buffer */
2N/Aint
2N/A_sync_field(FIELD *f)
2N/A{
2N/A int v = TRUE;
2N/A
2N/A if (Connected(f) && Posted(f) && Visible(f)) {
2N/A if (isCurrent(f)) {
2N/A FORM * p = f -> form;
2N/A WINDOW * w = W(p);
2N/A
2N/A Clr(p, WIN_CHG | BUF_CHG);
2N/A
2N/A Y(p) = 0;
2N/A X(p) = 0;
2N/A T(p) = 0;
2N/A B(p) = 0;
2N/A (void) werase(w);
2N/A
2N/A if (Opt(f, O_PUBLIC) && Justified(f))
2N/A unjustify(f, w);
2N/A else
2N/A _buf_to_win(f, w);
2N/A
2N/A Set(f, TOP_CHG);
2N/A (void) _update_current(p);
2N/A } else
2N/A v = display_field(f);
2N/A }
2N/A Set(f, USR_CHG);
2N/A
2N/A return (v ? E_OK : E_SYSTEM_ERROR);
2N/A}
2N/A
2N/A/* _sync_attrs - sync the field after a change to a field attribute */
2N/Aint
2N/A_sync_attrs(FIELD *f)
2N/A{
2N/A int v = TRUE;
2N/A
2N/A if (Connected(f) && Posted(f) && Visible(f)) {
2N/A if (isCurrent(f)) {
2N/A FORM * p = f -> form;
2N/A WINDOW * w = W(p);
2N/A
2N/A _sync_buffer(p);
2N/A
2N/A wbkgdset(w, Pad(f) | Back(f));
2N/A (void) wattrset(w, Fore(f));
2N/A (void) werase(w);
2N/A
2N/A if (Opt(f, O_PUBLIC)) {
2N/A if (Justified(f))
2N/A unjustify(f, w);
2N/A else
2N/A _buf_to_win(f, w);
2N/A } else {
2N/A (void) copywin(w, Sub(p), 0, 0, f -> frow,
2N/A f -> fcol, f -> rows - 1, f -> cols - 1,
2N/A FALSE);
2N/A wsyncup(Sub(p));
2N/A _buf_to_win(f, w);
2N/A }
2N/A Set(f, TOP_CHG);
2N/A (void) _update_current(p);
2N/A } else
2N/A v = display_field(f);
2N/A }
2N/A return (v ? E_OK : E_SYSTEM_ERROR);
2N/A}
2N/A
2N/Aint
2N/A_sync_opts(FIELD *f, OPTIONS opts)
2N/A{
2N/A int v = TRUE;
2N/A OPTIONS oldopts = f -> opts;
2N/A OPTIONS x = opts ^ oldopts;
2N/A /* x & opt indicates option opt has changed state */
2N/A f -> opts = opts;
2N/A
2N/A if (Connected(f)) {
2N/A if (isCurrent(f)) {
2N/A f -> opts = oldopts;
2N/A return (E_CURRENT);
2N/A }
2N/A if (Posted(f) && OnPage(f)) {
2N/A if (x & O_VISIBLE) {
2N/A if (Opt(f, O_VISIBLE))
2N/A v = display_field(f);
2N/A else
2N/A v = erase_field(f);
2N/A } else if (x & O_PUBLIC) {
2N/A if (Opt(f, O_VISIBLE))
2N/A v = display_field(f);
2N/A }
2N/A }
2N/A }
2N/A
2N/A if (x & O_STATIC) {
2N/A BOOLEAN onerow = OneRow(f);
2N/A int max = f->maxgrow;
2N/A
2N/A if (Opt(f, O_STATIC)) { /* growth being turned off */
2N/A Clr(f, GROWABLE);
2N/A
2N/A if (onerow && f->cols == f->dcols &&
2N/A Just(f) != NO_JUSTIFICATION && Posted(f) &&
2N/A OnPage(f) && Opt(f, O_VISIBLE)) {
2N/A (void) display_field(f);
2N/A }
2N/A } else if (!max || (onerow && f->dcols < max) ||
2N/A (!onerow && f->drows < max)) {
2N/A Set(f, GROWABLE);
2N/A
2N/A if (onerow && Just(f) != NO_JUSTIFICATION &&
2N/A Posted(f) && OnPage(f) && Opt(f, O_VISIBLE)) {
2N/A (void) display_field(f);
2N/A }
2N/A }
2N/A }
2N/A
2N/A return (v ? E_OK : E_SYSTEM_ERROR);
2N/A}
2N/A
2N/A/* _validate - validate current field */
2N/Aint
2N/A_validate(FORM *f)
2N/A{
2N/A FIELD * c = C(f);
2N/A
2N/A _sync_buffer(f);
2N/A
2N/A if (Status(f, BUF_CHG) || !Opt(c, O_PASSOK)) {
2N/A if (CheckField(c)) {
2N/A Clr(f, BUF_CHG);
2N/A Set(c, USR_CHG);
2N/A (void) _sync_linked(c);
2N/A } else
2N/A return (FALSE);
2N/A }
2N/A return (TRUE);
2N/A}
2N/A
2N/A/*
2N/A * _set_current_field - change current field on form f to given field.
2N/A * POSTED flag is set unless this is called from post_form().
2N/A */
2N/Aint
2N/A_set_current_field(FORM *f, FIELD *field)
2N/A{
2N/A WINDOW * w = W(f);
2N/A FIELD * c = C(f);
2N/A
2N/A if (c != field || ! Status(f, POSTED)) {
2N/A if (w) {
2N/A if (Visible(c)) {
2N/A (void) _update_current(f);
2N/A
2N/A if (Opt(c, O_PUBLIC)) {
2N/A if (Scrollable(c)) {
2N/A if (T(f) == 0)
2N/A Clr(c, TOP_CHG);
2N/A else
2N/A Set(c, TOP_CHG);
2N/A } else if (Justified(c)) {
2N/A (void) werase(w);
2N/A justify(c, w);
2N/A wsyncup(w);
2N/A }
2N/A }
2N/A }
2N/A (void) delwin(w);
2N/A }
2N/A c = field;
2N/A
2N/A if (!Opt(c, O_PUBLIC) || Scrollable(c))
2N/A w = newwin(c -> drows, c -> dcols, 0, 0);
2N/A else
2N/A w = derwin(Sub(f), c -> rows, c -> cols, c -> frow,
2N/A c -> fcol);
2N/A
2N/A if (!w)
2N/A return (E_SYSTEM_ERROR);
2N/A
2N/A C(f) = c;
2N/A W(f) = w;
2N/A wbkgdset(w, Pad(c) | Back(c));
2N/A (void) wattrset(w, Fore(c));
2N/A
2N/A if (!Opt(c, O_PUBLIC) || Scrollable(c)) {
2N/A (void) werase(w);
2N/A _buf_to_win(c, w);
2N/A } else if (Justified(c)) {
2N/A (void) werase(w);
2N/A unjustify(c, w);
2N/A wsyncup(w);
2N/A }
2N/A (void) untouchwin(w);
2N/A Clr(f, WIN_CHG | BUF_CHG);
2N/A }
2N/A Y(f) = 0;
2N/A X(f) = 0;
2N/A T(f) = 0;
2N/A B(f) = 0;
2N/A return (E_OK);
2N/A}
2N/A
2N/A/*
2N/A * _set_form_page - display given page and set current field to c.
2N/A * if c is null, then set current field to first field on page.
2N/A * POSTED flag is set unless this is called from post_form().
2N/A */
2N/Aint
2N/A_set_form_page(FORM *f, int page, FIELD *c)
2N/A{
2N/A if (P(f) != page || ! Status(f, POSTED)) {
2N/A FIELD * x = f -> field [Smin(f, page)];
2N/A FIELD * p = x;
2N/A
2N/A (void) werase(Sub(f));
2N/A P(f) = page;
2N/A
2N/A do {
2N/A if (Opt(p, O_VISIBLE))
2N/A if (!display_field(p))
2N/A return (E_SYSTEM_ERROR);
2N/A p = p -> snext;
2N/A
2N/A } while (p != x);
2N/A
2N/A return (c ? _set_current_field(f, c) : _first_field(f));
2N/A }
2N/A return (E_OK);
2N/A}