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.8 */
32
33 /*LINTLIBRARY*/
34
35 #include <sys/types.h>
36 #include <stdlib.h>
37 #include "utility.h"
38
39 #define MAX_BUF 81
40
41 /* default form */
42
43 static FORM default_form =
44 {
45 0, /* status */
46 0, /* rows */
47 0, /* cols */
48 0, /* currow */
49 0, /* curcol */
50 0, /* toprow */
51 0, /* begincol */
52 -1, /* maxfield */
53 -1, /* maxpage */
54 -1, /* curpage */
55 O_NL_OVERLOAD |
56 O_BS_OVERLOAD, /* opts */
57 (WINDOW *) 0, /* win */
58 (WINDOW *) 0, /* sub */
59 (WINDOW *) 0, /* w */
60 (FIELD **) 0, /* field */
61 (FIELD *) 0, /* current */
62 (_PAGE *) 0, /* page */
63 (char *) 0, /* usrptr */
64 (PTF_void) 0, /* forminit */
65 (PTF_void) 0, /* formterm */
66 (PTF_void) 0, /* fieldinit */
67 (PTF_void) 0, /* fieldterm */
68 };
69
70 FORM * _DEFAULT_FORM = &default_form;
71
72 /*
73 * insert - insert field f into sorted list pointed
74 * to by head. return (possibly new) head of list.
75 */
76 static FIELD *
insert(FIELD * f,FIELD * head)77 insert(FIELD *f, FIELD *head)
78 {
79 FIELD *p;
80 FIELD *newhead;
81 int frow, fcol;
82
83 if (head) {
84 p = newhead = head;
85
86 frow = f->frow;
87 fcol = f->fcol;
88
89 while ((p->frow < frow) ||
90 (p->frow == frow && p->fcol < fcol)) {
91 p = p->snext;
92
93 if (p == head) {
94 head = (FIELD *) 0;
95 break;
96 }
97 }
98 f->snext = p;
99 f->sprev = p->sprev;
100 f->snext->sprev = f;
101 f->sprev->snext = f;
102
103 if (p == head)
104 newhead = f; /* insert at head of list */
105 } else
106 newhead = f->sprev = f->snext = f; /* initialize new list */
107
108 return (newhead);
109 }
110
111 /* sort_form - sort fields on form(per page) */
112 static void
sort_form(FORM * f)113 sort_form(FORM *f)
114 {
115 FIELD **field;
116 FIELD *p;
117 int i, page, pmin, pmax;
118
119 field = f->field;
120
121 for (page = 0; page < f->maxpage; ++page) { /* for each page */
122 p = (FIELD *) 0;
123
124 pmin = Pmin(f, page);
125 pmax = Pmax(f, page);
126
127 for (i = pmin; i <= pmax; ++i) { /* for each field */
128 field[i]->index = i;
129 field[i]->page = page;
130
131 p = insert(field[i], p);
132 }
133 Smin(f, page) = p->index; /* set sorted min */
134 Smax(f, page) = p->sprev->index; /* set sorted max */
135 }
136 }
137
138 /* merge - xmax/ymax is the minimum window size to hold field f */
139 static void
merge(FIELD * f,FORM * form)140 merge(FIELD *f, FORM *form) /* adjust form dimensions to include field f */
141 {
142 int xmax = f->fcol + f->cols;
143 int ymax = f->frow + f->rows;
144
145 if (form->rows < ymax)
146 form->rows = ymax;
147 if (form->cols < xmax)
148 form->cols = xmax;
149 }
150
151 /* disconnect_fields - disconnect fields from form */
152 static void
disconnect_fields(FORM * form)153 disconnect_fields(FORM *form)
154 {
155 FIELD **f = form->field;
156
157 if (f)
158 while (*f) {
159 if ((*f)->form == form)
160 (*f)->form = (FORM *) 0;
161 ++f;
162 }
163
164 form->rows = 0;
165 form->cols = 0;
166 form->maxfield = -1;
167 form->maxpage = -1;
168 form->field = (FIELD **) 0;
169 }
170
171 /* connect_fields - connect fields to form */
172 static int
connect_fields(FORM * f,FIELD ** x)173 connect_fields(FORM *f, FIELD **x)
174 {
175 _PAGE * page;
176
177 int nf, /* number of fields */
178 np; /* number of pages */
179 int i;
180
181 f->field = x;
182 f->maxfield = 0;
183 f->maxpage = 0;
184
185 if (!x)
186 return (E_OK); /* null field array */
187
188 for (nf = 0, np = 0; x[nf]; ++nf) {
189 if (nf == 0 || Status(x[nf], NEW_PAGE))
190 ++np; /* count pages */
191
192 if (x[nf]->form)
193 return (E_CONNECTED);
194 else
195 x[nf]->form = f; /* connect field to form */
196 }
197 if (nf == 0)
198 return (E_BAD_ARGUMENT); /* no fields */
199
200 if (arrayAlloc(f->page, np, _PAGE)) {
201 page = f->page;
202
203 for (i = 0; i < nf; ++i) {
204 if (i == 0)
205 page->pmin = i;
206
207 else if (Status(x[i], NEW_PAGE)) {
208 page->pmax = i - 1;
209 ++page;
210 page->pmin = i;
211 }
212 merge(x[i], f);
213 }
214 page->pmax = nf - 1;
215 f->maxfield = nf;
216 f->maxpage = np;
217 sort_form(f);
218 return (E_OK);
219 }
220 return (E_SYSTEM_ERROR);
221 }
222
223 FORM *
new_form(FIELD ** field)224 new_form(FIELD **field)
225 {
226 FORM *f;
227
228 if (Alloc(f, FORM)) {
229 *f = *_DEFAULT_FORM;
230
231 if (connect_fields(f, field) == E_OK) {
232 if (f->maxpage) {
233 P(f) = 0;
234 C(f) = _first_active(f);
235 } else {
236 P(f) = -1;
237 C(f) = (FIELD *) 0;
238 }
239 return (f);
240 }
241 }
242 (void) free_form(f);
243 return ((FORM *) 0);
244 }
245
246 int
free_form(FORM * f)247 free_form(FORM *f)
248 {
249 if (!f)
250 return (E_BAD_ARGUMENT);
251
252 if (Status(f, POSTED))
253 return (E_POSTED);
254
255 disconnect_fields(f);
256 Free(f->page);
257 Free(f);
258 return (E_OK);
259 }
260
261 int
set_form_fields(FORM * f,FIELD ** fields)262 set_form_fields(FORM *f, FIELD **fields)
263 {
264 FIELD **p;
265 int v;
266
267 if (!f)
268 return (E_BAD_ARGUMENT);
269
270 if (Status(f, POSTED))
271 return (E_POSTED);
272
273 p = f->field;
274 disconnect_fields(f);
275
276 if ((v = connect_fields(f, fields)) == E_OK) {
277 if (f->maxpage) {
278 P(f) = 0;
279 C(f) = _first_active(f);
280 } else {
281 P(f) = -1;
282 C(f) = (FIELD *) 0;
283 }
284 } else
285 (void) connect_fields(f, p); /* reconnect original fields */
286 return (v);
287 }
288
289 FIELD **
form_fields(FORM * f)290 form_fields(FORM *f)
291 {
292 return (Form(f)->field);
293 }
294
295 int
field_count(FORM * f)296 field_count(FORM *f)
297 {
298 return (Form(f)->maxfield);
299 }
300
301 int
scale_form(FORM * f,int * rows,int * cols)302 scale_form(FORM *f, int *rows, int *cols)
303 {
304 if (!f)
305 return (E_BAD_ARGUMENT);
306
307 if (!f->field)
308 return (E_NOT_CONNECTED);
309
310 *rows = f->rows;
311 *cols = f->cols;
312 return (E_OK);
313 }
314
315 BOOLEAN
data_behind(FORM * f)316 data_behind(FORM *f)
317 {
318 return (OneRow(C(f)) ? B(f) != 0 : T(f) != 0);
319 }
320
321 /* _data_ahead - return ptr to last non-pad char in v[n] (v on failure) */
322 static char *
_data_ahead(char * v,int pad,int n)323 _data_ahead(char *v, int pad, int n)
324 {
325 char *vend = v + n;
326 while (vend > v && *(vend - 1) == pad) --vend;
327 return (vend);
328 }
329
330 BOOLEAN
data_ahead(FORM * f)331 data_ahead(FORM *f)
332 {
333 static char buf[ MAX_BUF ];
334 char *bptr = buf;
335 WINDOW *w = W(f);
336 FIELD *c = C(f);
337 int ret = FALSE;
338 int pad = Pad(c);
339 int cols = c->cols;
340 int dcols;
341 int drows;
342 int flag = cols > MAX_BUF - 1;
343 int start;
344 int chunk;
345
346 if (flag)
347 bptr = malloc(cols + 1);
348
349 if (OneRow(c)) {
350 dcols = c->dcols;
351 start = B(f) + cols;
352
353 while (start < dcols) {
354 chunk = MIN(cols, dcols - start);
355 (void) wmove(w, 0, start);
356 (void) winnstr(w, bptr, chunk);
357
358 if (bptr != _data_ahead(bptr, pad, chunk)) {
359 ret = (TRUE);
360 break;
361 }
362
363 start += cols;
364 }
365 } else { /* else multi-line field */
366 drows = c->drows;
367 start = T(f) + c->rows;
368
369 while (start < drows) {
370 (void) wmove(w, start++, 0);
371 (void) winnstr(w, bptr, cols);
372
373 if (bptr != _data_ahead(bptr, pad, cols)) {
374 ret = TRUE;
375 break;
376 }
377 }
378 }
379
380 if (flag)
381 (void) free(bptr);
382
383 (void) wmove(w, Y(f), X(f));
384 return (ret);
385 }
386