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