form.c revision 7c478bd95313f5f23a4c958a745db2134aa03244
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License, Version 1.0 only
* (the "License"). You may not use this file except in compliance
* with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/* Copyright (c) 1988 AT&T */
/* All Rights Reserved */
/*
* Copyright (c) 1997, by Sun Microsystems, Inc.
* All rights reserved.
*/
#pragma ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.8 */
/*LINTLIBRARY*/
#include <sys/types.h>
#include <stdlib.h>
#include "utility.h"
#define MAX_BUF 81
/* default form */
static FORM default_form =
{
0, /* status */
0, /* rows */
0, /* cols */
0, /* currow */
0, /* curcol */
0, /* toprow */
0, /* begincol */
-1, /* maxfield */
-1, /* maxpage */
-1, /* curpage */
O_NL_OVERLOAD |
O_BS_OVERLOAD, /* opts */
(WINDOW *) 0, /* win */
(WINDOW *) 0, /* sub */
(WINDOW *) 0, /* w */
(FIELD **) 0, /* field */
(FIELD *) 0, /* current */
(_PAGE *) 0, /* page */
(char *) 0, /* usrptr */
(PTF_void) 0, /* forminit */
(PTF_void) 0, /* formterm */
(PTF_void) 0, /* fieldinit */
(PTF_void) 0, /* fieldterm */
};
FORM * _DEFAULT_FORM = &default_form;
/*
* insert - insert field f into sorted list pointed
* to by head. return (possibly new) head of list.
*/
static FIELD *
insert(FIELD *f, FIELD *head)
{
FIELD *p;
FIELD *newhead;
int frow, fcol;
if (head) {
p = newhead = head;
frow = f->frow;
fcol = f->fcol;
while ((p->frow < frow) ||
(p->frow == frow && p->fcol < fcol)) {
p = p->snext;
if (p == head) {
head = (FIELD *) 0;
break;
}
}
f->snext = p;
f->sprev = p->sprev;
f->snext->sprev = f;
f->sprev->snext = f;
if (p == head)
newhead = f; /* insert at head of list */
} else
newhead = f->sprev = f->snext = f; /* initialize new list */
return (newhead);
}
/* sort_form - sort fields on form(per page) */
static void
sort_form(FORM *f)
{
FIELD **field;
FIELD *p;
int i, page, pmin, pmax;
field = f->field;
for (page = 0; page < f->maxpage; ++page) { /* for each page */
p = (FIELD *) 0;
pmin = Pmin(f, page);
pmax = Pmax(f, page);
for (i = pmin; i <= pmax; ++i) { /* for each field */
field[i]->index = i;
field[i]->page = page;
p = insert(field[i], p);
}
Smin(f, page) = p->index; /* set sorted min */
Smax(f, page) = p->sprev->index; /* set sorted max */
}
}
/* merge - xmax/ymax is the minimum window size to hold field f */
static void
merge(FIELD *f, FORM *form) /* adjust form dimensions to include field f */
{
int xmax = f->fcol + f->cols;
int ymax = f->frow + f->rows;
if (form->rows < ymax)
form->rows = ymax;
if (form->cols < xmax)
form->cols = xmax;
}
/* disconnect_fields - disconnect fields from form */
static void
disconnect_fields(FORM *form)
{
FIELD **f = form->field;
if (f)
while (*f) {
if ((*f)->form == form)
(*f)->form = (FORM *) 0;
++f;
}
form->rows = 0;
form->cols = 0;
form->maxfield = -1;
form->maxpage = -1;
form->field = (FIELD **) 0;
}
/* connect_fields - connect fields to form */
static int
connect_fields(FORM *f, FIELD **x)
{
_PAGE * page;
int nf, /* number of fields */
np; /* number of pages */
int i;
f->field = x;
f->maxfield = 0;
f->maxpage = 0;
if (!x)
return (E_OK); /* null field array */
for (nf = 0, np = 0; x[nf]; ++nf) {
if (nf == 0 || Status(x[nf], NEW_PAGE))
++np; /* count pages */
if (x[nf]->form)
return (E_CONNECTED);
else
x[nf]->form = f; /* connect field to form */
}
if (nf == 0)
return (E_BAD_ARGUMENT); /* no fields */
if (arrayAlloc(f->page, np, _PAGE)) {
page = f->page;
for (i = 0; i < nf; ++i) {
if (i == 0)
page->pmin = i;
else if (Status(x[i], NEW_PAGE)) {
page->pmax = i - 1;
++page;
page->pmin = i;
}
merge(x[i], f);
}
page->pmax = nf - 1;
f->maxfield = nf;
f->maxpage = np;
sort_form(f);
return (E_OK);
}
return (E_SYSTEM_ERROR);
}
FORM *
new_form(FIELD **field)
{
FORM *f;
if (Alloc(f, FORM)) {
*f = *_DEFAULT_FORM;
if (connect_fields(f, field) == E_OK) {
if (f->maxpage) {
P(f) = 0;
C(f) = _first_active(f);
} else {
P(f) = -1;
C(f) = (FIELD *) 0;
}
return (f);
}
}
(void) free_form(f);
return ((FORM *) 0);
}
int
free_form(FORM *f)
{
if (!f)
return (E_BAD_ARGUMENT);
if (Status(f, POSTED))
return (E_POSTED);
disconnect_fields(f);
Free(f->page);
Free(f);
return (E_OK);
}
int
set_form_fields(FORM *f, FIELD **fields)
{
FIELD **p;
int v;
if (!f)
return (E_BAD_ARGUMENT);
if (Status(f, POSTED))
return (E_POSTED);
p = f->field;
disconnect_fields(f);
if ((v = connect_fields(f, fields)) == E_OK) {
if (f->maxpage) {
P(f) = 0;
C(f) = _first_active(f);
} else {
P(f) = -1;
C(f) = (FIELD *) 0;
}
} else
(void) connect_fields(f, p); /* reconnect original fields */
return (v);
}
FIELD **
form_fields(FORM *f)
{
return (Form(f)->field);
}
int
field_count(FORM *f)
{
return (Form(f)->maxfield);
}
int
scale_form(FORM *f, int *rows, int *cols)
{
if (!f)
return (E_BAD_ARGUMENT);
if (!f->field)
return (E_NOT_CONNECTED);
*rows = f->rows;
*cols = f->cols;
return (E_OK);
}
BOOLEAN
data_behind(FORM *f)
{
return (OneRow(C(f)) ? B(f) != 0 : T(f) != 0);
}
/* _data_ahead - return ptr to last non-pad char in v[n] (v on failure) */
static char *
_data_ahead(char *v, int pad, int n)
{
char *vend = v + n;
while (vend > v && *(vend - 1) == pad) --vend;
return (vend);
}
BOOLEAN
data_ahead(FORM *f)
{
static char buf[ MAX_BUF ];
char *bptr = buf;
WINDOW *w = W(f);
FIELD *c = C(f);
int ret = FALSE;
int pad = Pad(c);
int cols = c->cols;
int dcols;
int drows;
int flag = cols > MAX_BUF - 1;
int start;
int chunk;
if (flag)
bptr = malloc(cols + 1);
if (OneRow(c)) {
dcols = c->dcols;
start = B(f) + cols;
while (start < dcols) {
chunk = MIN(cols, dcols - start);
(void) wmove(w, 0, start);
(void) winnstr(w, bptr, chunk);
if (bptr != _data_ahead(bptr, pad, chunk)) {
ret = (TRUE);
break;
}
start += cols;
}
} else { /* else multi-line field */
drows = c->drows;
start = T(f) + c->rows;
while (start < drows) {
(void) wmove(w, start++, 0);
(void) winnstr(w, bptr, cols);
if (bptr != _data_ahead(bptr, pad, cols)) {
ret = TRUE;
break;
}
}
}
if (flag)
(void) free(bptr);
(void) wmove(w, Y(f), X(f));
return (ret);
}