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