#include <sys/types.h>
#include <stdlib.h>
#include "utility.h"
#define MAX_BUF 81
static FORM default_form =
{
0,
0,
0,
0,
0,
0,
0,
-1,
-1,
-1,
O_NL_OVERLOAD |
O_BS_OVERLOAD,
(WINDOW *) 0,
(WINDOW *) 0,
(WINDOW *) 0,
(FIELD **) 0,
(FIELD *) 0,
(_PAGE *) 0,
(char *) 0,
(PTF_void) 0,
(PTF_void) 0,
(PTF_void) 0,
(PTF_void) 0,
};
FORM * _DEFAULT_FORM = &default_form;
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;
} else
newhead = f->sprev = f->snext = f;
return (newhead);
}
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) {
p = (FIELD *) 0;
pmin = Pmin(f, page);
pmax = Pmax(f, page);
for (i = pmin; i <= pmax; ++i) {
field[i]->index = i;
field[i]->page = page;
p = insert(field[i], p);
}
Smin(f, page) = p->index;
Smax(f, page) = p->sprev->index;
}
}
static void
merge(FIELD *f, FORM *form)
{
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;
}
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;
}
static int
connect_fields(FORM *f, FIELD **x)
{
_PAGE * page;
int nf,
np;
int i;
f->field = x;
f->maxfield = 0;
f->maxpage = 0;
if (!x)
return (E_OK);
for (nf = 0, np = 0; x[nf]; ++nf) {
if (nf == 0 || Status(x[nf], NEW_PAGE))
++np;
if (x[nf]->form)
return (E_CONNECTED);
else
x[nf]->form = f;
}
if (nf == 0)
return (E_BAD_ARGUMENT);
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);
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);
}
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 {
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);
}