1 /**************************************************************************** 2 * Copyright 2020,2021 Thomas E. Dickey * 3 * Copyright 1998-2010,2012 Free Software Foundation, Inc. * 4 * * 5 * Permission is hereby granted, free of charge, to any person obtaining a * 6 * copy of this software and associated documentation files (the * 7 * "Software"), to deal in the Software without restriction, including * 8 * without limitation the rights to use, copy, modify, merge, publish, * 9 * distribute, distribute with modifications, sublicense, and/or sell * 10 * copies of the Software, and to permit persons to whom the Software is * 11 * furnished to do so, subject to the following conditions: * 12 * * 13 * The above copyright notice and this permission notice shall be included * 14 * in all copies or substantial portions of the Software. * 15 * * 16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * 17 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * 18 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * 19 * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, * 20 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR * 21 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR * 22 * THE USE OR OTHER DEALINGS IN THE SOFTWARE. * 23 * * 24 * Except as contained in this notice, the name(s) of the above copyright * 25 * holders shall not be used in advertising or otherwise to promote the * 26 * sale, use or other dealings in this Software without prior written * 27 * authorization. * 28 ****************************************************************************/ 29 30 /**************************************************************************** 31 * Author: Juergen Pfeifer, 1995,1997 * 32 ****************************************************************************/ 33 34 #include "form.priv.h" 35 36 MODULE_ID("$Id: frm_def.c,v 1.30 2021/03/27 23:49:58 tom Exp $") 37 38 /* this can't be readonly */ 39 static FORM default_form = 40 { 41 0, /* status */ 42 0, /* rows */ 43 0, /* cols */ 44 0, /* currow */ 45 0, /* curcol */ 46 0, /* toprow */ 47 0, /* begincol */ 48 -1, /* maxfield */ 49 -1, /* maxpage */ 50 -1, /* curpage */ 51 ALL_FORM_OPTS, /* opts */ 52 (WINDOW *)0, /* win */ 53 (WINDOW *)0, /* sub */ 54 (WINDOW *)0, /* w */ 55 (FIELD **)0, /* field */ 56 (FIELD *)0, /* current */ 57 (_PAGE *) 0, /* page */ 58 (char *)0, /* usrptr */ 59 NULL, /* forminit */ 60 NULL, /* formterm */ 61 NULL, /* fieldinit */ 62 NULL /* fieldterm */ 63 }; 64 65 FORM_EXPORT_VAR(FORM *) _nc_Default_Form = &default_form; 66 67 /*--------------------------------------------------------------------------- 68 | Facility : libnform 69 | Function : static FIELD *Insert_Field_By_Position( 70 | FIELD *new_field, 71 | FIELD *head ) 72 | 73 | Description : Insert new_field into sorted fieldlist with head "head" 74 | and return new head of sorted fieldlist. Sorting 75 | criteria is (row,column). This is a circular list. 76 | 77 | Return Values : New head of sorted fieldlist 78 +--------------------------------------------------------------------------*/ 79 static FIELD * 80 Insert_Field_By_Position(FIELD *newfield, FIELD *head) 81 { 82 FIELD *current, *newhead; 83 84 assert(newfield); 85 86 if (!head) 87 { /* empty list is trivial */ 88 newhead = newfield->snext = newfield->sprev = newfield; 89 } 90 else 91 { 92 newhead = current = head; 93 while ((current->frow < newfield->frow) || 94 ((current->frow == newfield->frow) && 95 (current->fcol < newfield->fcol))) 96 { 97 current = current->snext; 98 if (current == head) 99 { /* We cycled through. Reset head to indicate that */ 100 head = (FIELD *)0; 101 break; 102 } 103 } 104 /* we leave the loop with current pointing to the field after newfield */ 105 newfield->snext = current; 106 newfield->sprev = current->sprev; 107 newfield->snext->sprev = newfield; 108 newfield->sprev->snext = newfield; 109 if (current == head) 110 newhead = newfield; 111 } 112 return (newhead); 113 } 114 115 /*--------------------------------------------------------------------------- 116 | Facility : libnform 117 | Function : static void Disconnect_Fields(FORM *form) 118 | 119 | Description : Break association between form and array of fields. 120 | 121 | Return Values : - 122 +--------------------------------------------------------------------------*/ 123 static void 124 Disconnect_Fields(FORM *form) 125 { 126 if (form->field) 127 { 128 FIELD **fields; 129 130 for (fields = form->field; *fields; fields++) 131 { 132 if (form == (*fields)->form) 133 (*fields)->form = (FORM *)0; 134 } 135 136 form->rows = form->cols = 0; 137 form->maxfield = form->maxpage = -1; 138 form->field = (FIELD **)0; 139 if (form->page) 140 free(form->page); 141 form->page = (_PAGE *) 0; 142 } 143 } 144 145 /*--------------------------------------------------------------------------- 146 | Facility : libnform 147 | Function : static int Connect_Fields(FORM *form, FIELD **fields) 148 | 149 | Description : Set association between form and array of fields. 150 | 151 | Return Values : E_OK - no error 152 | E_CONNECTED - a field is already connected 153 | E_BAD_ARGUMENT - Invalid form pointer or field array 154 | E_SYSTEM_ERROR - not enough memory 155 +--------------------------------------------------------------------------*/ 156 static int 157 Connect_Fields(FORM *form, FIELD **fields) 158 { 159 int field_cnt, j; 160 int page_nr; 161 _PAGE *pg; 162 163 T((T_CALLED("Connect_Fields(%p,%p)"), (void *)form, (void *)fields)); 164 165 assert(form); 166 167 form->field = fields; 168 form->maxfield = 0; 169 form->maxpage = 0; 170 171 if (!fields) 172 RETURN(E_OK); 173 174 page_nr = 0; 175 /* store formpointer in fields and count pages */ 176 for (field_cnt = 0; fields[field_cnt]; field_cnt++) 177 { 178 if (fields[field_cnt]->form) 179 RETURN(E_CONNECTED); 180 if (field_cnt == 0 || 181 (fields[field_cnt]->status & _NEWPAGE)) 182 page_nr++; 183 fields[field_cnt]->form = form; 184 } 185 if (field_cnt == 0 || (short)field_cnt < 0) 186 RETURN(E_BAD_ARGUMENT); 187 188 /* allocate page structures */ 189 if ((pg = typeMalloc(_PAGE, page_nr)) != (_PAGE *) 0) 190 { 191 T((T_CREATE("_PAGE %p"), (void *)pg)); 192 form->page = pg; 193 } 194 else 195 RETURN(E_SYSTEM_ERROR); 196 197 /* Cycle through fields and calculate page boundaries as well as 198 size of the form */ 199 for (j = 0; j < field_cnt; j++) 200 { 201 int maximum_row_in_field; 202 int maximum_col_in_field; 203 204 if (j == 0) 205 pg->pmin = (short)j; 206 else 207 { 208 if (fields[j]->status & _NEWPAGE) 209 { 210 pg->pmax = (short)(j - 1); 211 pg++; 212 pg->pmin = (short)j; 213 } 214 } 215 216 maximum_row_in_field = fields[j]->frow + fields[j]->rows; 217 maximum_col_in_field = fields[j]->fcol + fields[j]->cols; 218 219 if (form->rows < maximum_row_in_field) 220 form->rows = (short)maximum_row_in_field; 221 if (form->cols < maximum_col_in_field) 222 form->cols = (short)maximum_col_in_field; 223 } 224 225 pg->pmax = (short)(field_cnt - 1); 226 form->maxfield = (short)field_cnt; 227 form->maxpage = (short)page_nr; 228 229 /* Sort fields on form pages */ 230 for (page_nr = 0; page_nr < form->maxpage; page_nr++) 231 { 232 FIELD *fld = (FIELD *)0; 233 234 for (j = form->page[page_nr].pmin; j <= form->page[page_nr].pmax; j++) 235 { 236 fields[j]->index = (short)j; 237 fields[j]->page = (short)page_nr; 238 fld = Insert_Field_By_Position(fields[j], fld); 239 } 240 if (fld) 241 { 242 form->page[page_nr].smin = fld->index; 243 form->page[page_nr].smax = fld->sprev->index; 244 } 245 else 246 { 247 form->page[page_nr].smin = 0; 248 form->page[page_nr].smax = 0; 249 } 250 } 251 RETURN(E_OK); 252 } 253 254 /*--------------------------------------------------------------------------- 255 | Facility : libnform 256 | Function : static int Associate_Fields(FORM *form, FIELD **fields) 257 | 258 | Description : Set association between form and array of fields. 259 | If there are fields, position to first active field. 260 | 261 | Return Values : E_OK - success 262 | E_BAD_ARGUMENT - Invalid form pointer or field array 263 | E_CONNECTED - a field is already connected 264 | E_SYSTEM_ERROR - not enough memory 265 +--------------------------------------------------------------------------*/ 266 NCURSES_INLINE static int 267 Associate_Fields(FORM *form, FIELD **fields) 268 { 269 int res = Connect_Fields(form, fields); 270 271 if (res == E_OK) 272 { 273 if (form->maxpage > 0) 274 { 275 form->curpage = 0; 276 form_driver(form, FIRST_ACTIVE_MAGIC); 277 } 278 else 279 { 280 form->curpage = -1; 281 form->current = (FIELD *)0; 282 } 283 } 284 return (res); 285 } 286 287 /*--------------------------------------------------------------------------- 288 | Facility : libnform 289 | Function : FORM *new_form_sp(SCREEN* sp, FIELD** fields ) 290 | 291 | Description : Create new form with given array of fields. 292 | 293 | Return Values : Pointer to form. NULL if error occurred. 294 ! Set errno: 295 | E_OK - success 296 | E_BAD_ARGUMENT - Invalid form pointer or field array 297 | E_CONNECTED - a field is already connected 298 | E_SYSTEM_ERROR - not enough memory 299 +--------------------------------------------------------------------------*/ 300 FORM_EXPORT(FORM *) 301 NCURSES_SP_NAME(new_form) (NCURSES_SP_DCLx FIELD **fields) 302 { 303 int err = E_SYSTEM_ERROR; 304 FORM *form = (FORM *)0; 305 306 T((T_CALLED("new_form(%p,%p)"), (void *)SP_PARM, (void *)fields)); 307 308 if (IsValidScreen(SP_PARM)) 309 { 310 form = typeMalloc(FORM, 1); 311 312 if (form) 313 { 314 T((T_CREATE("form %p"), (void *)form)); 315 *form = *_nc_Default_Form; 316 /* This ensures win and sub are always non-null, 317 so we can derive always the SCREEN that this form is 318 running on. */ 319 form->win = StdScreen(SP_PARM); 320 form->sub = StdScreen(SP_PARM); 321 if ((err = Associate_Fields(form, fields)) != E_OK) 322 { 323 free_form(form); 324 form = (FORM *)0; 325 } 326 } 327 } 328 329 if (!form) 330 SET_ERROR(err); 331 332 returnForm(form); 333 } 334 335 /*--------------------------------------------------------------------------- 336 | Facility : libnform 337 | Function : FORM* new_form(FIELD** fields ) 338 | 339 | Description : Create new form with given array of fields. 340 | 341 | Return Values : Pointer to form. NULL if error occurred. 342 ! Set errno: 343 | E_OK - success 344 | E_BAD_ARGUMENT - Invalid form pointer or field array 345 | E_CONNECTED - a field is already connected 346 | E_SYSTEM_ERROR - not enough memory 347 +--------------------------------------------------------------------------*/ 348 #if NCURSES_SP_FUNCS 349 FORM_EXPORT(FORM *) 350 new_form(FIELD **fields) 351 { 352 return NCURSES_SP_NAME(new_form) (CURRENT_SCREEN, fields); 353 } 354 #endif 355 356 /*--------------------------------------------------------------------------- 357 | Facility : libnform 358 | Function : int free_form( FORM *form ) 359 | 360 | Description : Release internal memory associated with form. 361 | 362 | Return Values : E_OK - no error 363 | E_BAD_ARGUMENT - invalid form pointer 364 | E_POSTED - form is posted 365 +--------------------------------------------------------------------------*/ 366 FORM_EXPORT(int) 367 free_form(FORM *form) 368 { 369 T((T_CALLED("free_form(%p)"), (void *)form)); 370 371 if (!form) 372 RETURN(E_BAD_ARGUMENT); 373 374 if (form->status & _POSTED) 375 RETURN(E_POSTED); 376 377 Disconnect_Fields(form); 378 if (form->page) 379 free(form->page); 380 free(form); 381 382 RETURN(E_OK); 383 } 384 385 /*--------------------------------------------------------------------------- 386 | Facility : libnform 387 | Function : int set_form_fields( FORM *form, FIELD **fields ) 388 | 389 | Description : Set a new association of an array of fields to a form 390 | 391 | Return Values : E_OK - no error 392 | E_BAD_ARGUMENT - Invalid form pointer or field array 393 | E_CONNECTED - a field is already connected 394 | E_POSTED - form is posted 395 | E_SYSTEM_ERROR - not enough memory 396 +--------------------------------------------------------------------------*/ 397 FORM_EXPORT(int) 398 set_form_fields(FORM *form, FIELD **fields) 399 { 400 FIELD **old; 401 int res; 402 403 T((T_CALLED("set_form_fields(%p,%p)"), (void *)form, (void *)fields)); 404 405 if (!form) 406 RETURN(E_BAD_ARGUMENT); 407 408 if (form->status & _POSTED) 409 RETURN(E_POSTED); 410 411 old = form->field; 412 Disconnect_Fields(form); 413 414 if ((res = Associate_Fields(form, fields)) != E_OK) 415 Connect_Fields(form, old); 416 417 RETURN(res); 418 } 419 420 /*--------------------------------------------------------------------------- 421 | Facility : libnform 422 | Function : FIELD **form_fields( const FORM *form ) 423 | 424 | Description : Retrieve array of fields 425 | 426 | Return Values : Pointer to field array 427 +--------------------------------------------------------------------------*/ 428 FORM_EXPORT(FIELD **) 429 form_fields(const FORM *form) 430 { 431 T((T_CALLED("form_field(%p)"), (const void *)form)); 432 returnFieldPtr(Normalize_Form(form)->field); 433 } 434 435 /*--------------------------------------------------------------------------- 436 | Facility : libnform 437 | Function : int field_count( const FORM *form ) 438 | 439 | Description : Retrieve number of fields 440 | 441 | Return Values : Number of fields, -1 if none are defined 442 +--------------------------------------------------------------------------*/ 443 FORM_EXPORT(int) 444 field_count(const FORM *form) 445 { 446 T((T_CALLED("field_count(%p)"), (const void *)form)); 447 448 returnCode(Normalize_Form(form)->maxfield); 449 } 450 451 /* frm_def.c ends here */ 452