1 /**************************************************************************** 2 * Copyright 2020 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.29 2020/12/11 23:47:16 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 int maximum_row_in_field, maximum_col_in_field; 162 _PAGE *pg; 163 164 T((T_CALLED("Connect_Fields(%p,%p)"), (void *)form, (void *)fields)); 165 166 assert(form); 167 168 form->field = fields; 169 form->maxfield = 0; 170 form->maxpage = 0; 171 172 if (!fields) 173 RETURN(E_OK); 174 175 page_nr = 0; 176 /* store formpointer in fields and count pages */ 177 for (field_cnt = 0; fields[field_cnt]; field_cnt++) 178 { 179 if (fields[field_cnt]->form) 180 RETURN(E_CONNECTED); 181 if (field_cnt == 0 || 182 (fields[field_cnt]->status & _NEWPAGE)) 183 page_nr++; 184 fields[field_cnt]->form = form; 185 } 186 if (field_cnt == 0 || (short)field_cnt < 0) 187 RETURN(E_BAD_ARGUMENT); 188 189 /* allocate page structures */ 190 if ((pg = typeMalloc(_PAGE, page_nr)) != (_PAGE *) 0) 191 { 192 T((T_CREATE("_PAGE %p"), (void *)pg)); 193 form->page = pg; 194 } 195 else 196 RETURN(E_SYSTEM_ERROR); 197 198 /* Cycle through fields and calculate page boundaries as well as 199 size of the form */ 200 for (j = 0; j < field_cnt; j++) 201 { 202 if (j == 0) 203 pg->pmin = (short)j; 204 else 205 { 206 if (fields[j]->status & _NEWPAGE) 207 { 208 pg->pmax = (short)(j - 1); 209 pg++; 210 pg->pmin = (short)j; 211 } 212 } 213 214 maximum_row_in_field = fields[j]->frow + fields[j]->rows; 215 maximum_col_in_field = fields[j]->fcol + fields[j]->cols; 216 217 if (form->rows < maximum_row_in_field) 218 form->rows = (short)maximum_row_in_field; 219 if (form->cols < maximum_col_in_field) 220 form->cols = (short)maximum_col_in_field; 221 } 222 223 pg->pmax = (short)(field_cnt - 1); 224 form->maxfield = (short)field_cnt; 225 form->maxpage = (short)page_nr; 226 227 /* Sort fields on form pages */ 228 for (page_nr = 0; page_nr < form->maxpage; page_nr++) 229 { 230 FIELD *fld = (FIELD *)0; 231 232 for (j = form->page[page_nr].pmin; j <= form->page[page_nr].pmax; j++) 233 { 234 fields[j]->index = (short)j; 235 fields[j]->page = (short)page_nr; 236 fld = Insert_Field_By_Position(fields[j], fld); 237 } 238 if (fld) 239 { 240 form->page[page_nr].smin = fld->index; 241 form->page[page_nr].smax = fld->sprev->index; 242 } 243 else 244 { 245 form->page[page_nr].smin = 0; 246 form->page[page_nr].smax = 0; 247 } 248 } 249 RETURN(E_OK); 250 } 251 252 /*--------------------------------------------------------------------------- 253 | Facility : libnform 254 | Function : static int Associate_Fields(FORM *form, FIELD **fields) 255 | 256 | Description : Set association between form and array of fields. 257 | If there are fields, position to first active field. 258 | 259 | Return Values : E_OK - success 260 | E_BAD_ARGUMENT - Invalid form pointer or field array 261 | E_CONNECTED - a field is already connected 262 | E_SYSTEM_ERROR - not enough memory 263 +--------------------------------------------------------------------------*/ 264 NCURSES_INLINE static int 265 Associate_Fields(FORM *form, FIELD **fields) 266 { 267 int res = Connect_Fields(form, fields); 268 269 if (res == E_OK) 270 { 271 if (form->maxpage > 0) 272 { 273 form->curpage = 0; 274 form_driver(form, FIRST_ACTIVE_MAGIC); 275 } 276 else 277 { 278 form->curpage = -1; 279 form->current = (FIELD *)0; 280 } 281 } 282 return (res); 283 } 284 285 /*--------------------------------------------------------------------------- 286 | Facility : libnform 287 | Function : FORM *new_form_sp(SCREEN* sp, FIELD** fields ) 288 | 289 | Description : Create new form with given array of fields. 290 | 291 | Return Values : Pointer to form. NULL if error occurred. 292 ! Set errno: 293 | E_OK - success 294 | E_BAD_ARGUMENT - Invalid form pointer or field array 295 | E_CONNECTED - a field is already connected 296 | E_SYSTEM_ERROR - not enough memory 297 +--------------------------------------------------------------------------*/ 298 FORM_EXPORT(FORM *) 299 NCURSES_SP_NAME(new_form) (NCURSES_SP_DCLx FIELD **fields) 300 { 301 int err = E_SYSTEM_ERROR; 302 FORM *form = (FORM *)0; 303 304 T((T_CALLED("new_form(%p,%p)"), (void *)SP_PARM, (void *)fields)); 305 306 if (IsValidScreen(SP_PARM)) 307 { 308 form = typeMalloc(FORM, 1); 309 310 if (form) 311 { 312 T((T_CREATE("form %p"), (void *)form)); 313 *form = *_nc_Default_Form; 314 /* This ensures win and sub are always non-null, 315 so we can derive always the SCREEN that this form is 316 running on. */ 317 form->win = StdScreen(SP_PARM); 318 form->sub = StdScreen(SP_PARM); 319 if ((err = Associate_Fields(form, fields)) != E_OK) 320 { 321 free_form(form); 322 form = (FORM *)0; 323 } 324 } 325 } 326 327 if (!form) 328 SET_ERROR(err); 329 330 returnForm(form); 331 } 332 333 /*--------------------------------------------------------------------------- 334 | Facility : libnform 335 | Function : FORM* new_form(FIELD** fields ) 336 | 337 | Description : Create new form with given array of fields. 338 | 339 | Return Values : Pointer to form. NULL if error occurred. 340 ! Set errno: 341 | E_OK - success 342 | E_BAD_ARGUMENT - Invalid form pointer or field array 343 | E_CONNECTED - a field is already connected 344 | E_SYSTEM_ERROR - not enough memory 345 +--------------------------------------------------------------------------*/ 346 #if NCURSES_SP_FUNCS 347 FORM_EXPORT(FORM *) 348 new_form(FIELD **fields) 349 { 350 return NCURSES_SP_NAME(new_form) (CURRENT_SCREEN, fields); 351 } 352 #endif 353 354 /*--------------------------------------------------------------------------- 355 | Facility : libnform 356 | Function : int free_form( FORM *form ) 357 | 358 | Description : Release internal memory associated with form. 359 | 360 | Return Values : E_OK - no error 361 | E_BAD_ARGUMENT - invalid form pointer 362 | E_POSTED - form is posted 363 +--------------------------------------------------------------------------*/ 364 FORM_EXPORT(int) 365 free_form(FORM *form) 366 { 367 T((T_CALLED("free_form(%p)"), (void *)form)); 368 369 if (!form) 370 RETURN(E_BAD_ARGUMENT); 371 372 if (form->status & _POSTED) 373 RETURN(E_POSTED); 374 375 Disconnect_Fields(form); 376 if (form->page) 377 free(form->page); 378 free(form); 379 380 RETURN(E_OK); 381 } 382 383 /*--------------------------------------------------------------------------- 384 | Facility : libnform 385 | Function : int set_form_fields( FORM *form, FIELD **fields ) 386 | 387 | Description : Set a new association of an array of fields to a form 388 | 389 | Return Values : E_OK - no error 390 | E_BAD_ARGUMENT - Invalid form pointer or field array 391 | E_CONNECTED - a field is already connected 392 | E_POSTED - form is posted 393 | E_SYSTEM_ERROR - not enough memory 394 +--------------------------------------------------------------------------*/ 395 FORM_EXPORT(int) 396 set_form_fields(FORM *form, FIELD **fields) 397 { 398 FIELD **old; 399 int res; 400 401 T((T_CALLED("set_form_fields(%p,%p)"), (void *)form, (void *)fields)); 402 403 if (!form) 404 RETURN(E_BAD_ARGUMENT); 405 406 if (form->status & _POSTED) 407 RETURN(E_POSTED); 408 409 old = form->field; 410 Disconnect_Fields(form); 411 412 if ((res = Associate_Fields(form, fields)) != E_OK) 413 Connect_Fields(form, old); 414 415 RETURN(res); 416 } 417 418 /*--------------------------------------------------------------------------- 419 | Facility : libnform 420 | Function : FIELD **form_fields( const FORM *form ) 421 | 422 | Description : Retrieve array of fields 423 | 424 | Return Values : Pointer to field array 425 +--------------------------------------------------------------------------*/ 426 FORM_EXPORT(FIELD **) 427 form_fields(const FORM *form) 428 { 429 T((T_CALLED("form_field(%p)"), (const void *)form)); 430 returnFieldPtr(Normalize_Form(form)->field); 431 } 432 433 /*--------------------------------------------------------------------------- 434 | Facility : libnform 435 | Function : int field_count( const FORM *form ) 436 | 437 | Description : Retrieve number of fields 438 | 439 | Return Values : Number of fields, -1 if none are defined 440 +--------------------------------------------------------------------------*/ 441 FORM_EXPORT(int) 442 field_count(const FORM *form) 443 { 444 T((T_CALLED("field_count(%p)"), (const void *)form)); 445 446 returnCode(Normalize_Form(form)->maxfield); 447 } 448 449 /* frm_def.c ends here */ 450