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