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