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 36MODULE_ID("$Id: frm_def.c,v 1.30 2021/03/27 23:49:58 tom Exp $") 37 38/* this can't be readonly */ 39static 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 65FORM_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+--------------------------------------------------------------------------*/ 79static FIELD * 80Insert_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+--------------------------------------------------------------------------*/ 123static void 124Disconnect_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+--------------------------------------------------------------------------*/ 156static int 157Connect_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+--------------------------------------------------------------------------*/ 266NCURSES_INLINE static int 267Associate_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+--------------------------------------------------------------------------*/ 300FORM_EXPORT(FORM *) 301NCURSES_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 349FORM_EXPORT(FORM *) 350new_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+--------------------------------------------------------------------------*/ 366FORM_EXPORT(int) 367free_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+--------------------------------------------------------------------------*/ 397FORM_EXPORT(int) 398set_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+--------------------------------------------------------------------------*/ 428FORM_EXPORT(FIELD **) 429form_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+--------------------------------------------------------------------------*/ 443FORM_EXPORT(int) 444field_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