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