xref: /illumos-gate/usr/src/lib/libeti/form/common/form.c (revision 7c478bd9)
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 *
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
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
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
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
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 *
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
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
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 **
290 form_fields(FORM *f)
291 {
292 	return (Form(f)->field);
293 }
294 
295 int
296 field_count(FORM *f)
297 {
298 	return (Form(f)->maxfield);
299 }
300 
301 int
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
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 *
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
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