added concrete implementations of putc(), getc(), getchar() and gets()
[tangerine.git] / workbench / classes / gadgets / aroslist / listclass.c
blob38503e23c9ff9379592f3fe6d11b7731ee9f6bb9
1 /*
2 Copyright © 1995-2005, The AROS Development Team. All rights reserved.
3 $Id$
5 AROS specific list class implementation.
6 */
8 #include <exec/types.h>
10 #include <proto/exec.h>
11 #include <proto/intuition.h>
12 #include <proto/utility.h>
13 #include <exec/memory.h>
14 #include <intuition/classusr.h>
15 #include <aros/asmcall.h>
16 #include <string.h>
18 #include "aroslist_intern.h"
19 #include <gadgets/aroslist.h>
21 #define DEBUG 0
23 #include <aros/debug.h>
25 #undef AROSListBase
26 #define AROSListBase ((struct LVBase *)(cl->cl_UserData))
29 /*****************************************************************************/
33 #define SETFLAG(flagvar, boolvar, flag) \
34 if (boolvar) \
35 flagvar |= flag; \
36 else \
37 flagvar &= ~flag;
41 /******************
42 ** List::Set() **
43 ******************/
45 STATIC VOID SetActive(LONG pos, struct ListData *data)
47 if (data->ld_Active != AROSV_List_Active_None)
49 data->ld_PointerArray[data->ld_Active]->le_Flags &= ~LEFLG_SELECTED;
52 if (pos != AROSV_List_Active_None)
54 data->ld_PointerArray[pos]->le_Flags |= LEFLG_SELECTED;
56 data->ld_Active = pos;
57 return;
59 STATIC _OM_SET(Class *cl, Object *o,struct opSet *msg)
61 IPTR retval = (IPTR)0;
63 const struct TagItem *tag, *tstate;
64 struct ListData *data;
66 data = INST_DATA(cl, o);
67 tstate = msg->ops_AttrList;
69 /* Set to 1 to signal visual changes */
70 while ((tag = NextTagItem(&tstate)) != NULL)
72 switch (tag->ti_Tag)
75 case AROSA_List_ConstructHook:
76 data->ld_ConstructHook = (struct Hook *)tag->ti_Data;
77 break;
79 case AROSA_List_DestructHook:
80 data->ld_DestructHook = (struct Hook *)tag->ti_Data;
81 break;
84 case AROSA_List_Active:
85 SetActive((LONG)tag->ti_Data, data);
86 break;
88 default:
89 break;
91 } /* switch (tag->ti_Tag) */
93 } /* while ((tag = NextTagItem(&tstate)) != NULL) */
95 ReturnPtr("list_set", IPTR, retval);
97 IPTR AROSList__OM_SET(Class *cl, Object *o,struct opSet *msg)
99 IPTR retval = DoSuperMethodA(cl, o, msg);
100 retval += _OM_SET(cl, o, msg);
101 return retval;
104 /*****************
105 ** List::New() **
106 *****************/
107 IPTR AROSList__OM_NEW(Class *cl, Object *o, struct opSet *msg)
109 o = (Object *)DoSuperMethodA(cl, o, (Msg)msg);
111 if (o)
113 struct ListData *data;
114 APTR *srcarray = NULL;
115 const struct TagItem *tag, *tstate;
117 ULONG puddlesz = 2008, threshsz = 1024;
119 D(bug("list, OM_NEW: obj returned from superclass\n"));
120 data = INST_DATA(cl, o);
121 memset(data, 0, sizeof (struct ListData));
123 /* Initialize the object's internal lists */
124 NewLEList(data->ld_EntryTables);
125 NewLEList(data->ld_UnusedEntries);
127 /* Parse for some init only tags */
128 tstate = msg->ops_AttrList;
129 while ((tag = NextTagItem(&tstate)) != NULL)
131 switch (tag->ti_Tag)
133 case AROSA_List_SourceArray:
134 srcarray = (APTR *)tag->ti_Data;
135 break;
137 case AROSA_List_PoolPuddleSize:
138 puddlesz = (ULONG)tag->ti_Data;
139 break;
141 case AROSA_List_PoolThreshSize:
142 threshsz = (ULONG)tag->ti_Data;
143 break;
144 case AROSA_List_Pool:
145 data->ld_Pool = (APTR)tag->ti_Data;
146 break;
148 } /* switch (tag->ti_Tag) */
150 } /* while (more tags in taglist) */
153 /* User supplied source array ? */
154 srcarray = (APTR *)GetTagData(AROSA_List_SourceArray, (IPTR) NULL, msg->ops_AttrList);
156 /* Allocate a bunch of free listentries */
157 data->ld_PointerArray = AllocEntries( (srcarray != NULL)
158 ? CountItems(srcarray)
159 : NUMENTRIES_TO_ADD,
160 data
163 if (!data->ld_Pool)
165 data->ld_Pool = CreatePool(MEMF_ANY, puddlesz, threshsz);
168 D(bug("listclass, OM_NEW: pointerarray = %p, pool = %p\n",
169 data->ld_PointerArray, data->ld_Pool));
171 if (!data->ld_PointerArray || !data->ld_Pool)
173 CoerceMethod(cl, o, OM_DISPOSE);
174 return (IPTR) NULL;
177 /* As default there is no active entry */
178 data->ld_Active = AROSV_List_Active_None;
180 /* Handle our special tags - overrides defaults. This must be done
181 before the AROSM_List_Insert call, because we must get the ConstructHook and
182 DestructHook tags */
184 _OM_SET(cl, o, msg);
186 if (srcarray)
188 DoMethod(o, AROSM_List_Insert, (IPTR) srcarray, AROSV_List_Insert_Top);
193 } /* if (object created) */
194 return ((IPTR)o);
198 /*********************
199 ** List::Dispose() **
200 *********************/
202 VOID AROSList__OM_DISPOSE(Class *cl, Object *o, Msg msg)
204 #warning TODO: Call destructhook too
206 struct ListData *data;
207 struct ListEntry *entry, *next;
209 data = INST_DATA(cl, o);
211 D(bug("Inside OM_DISPOSE\n"));
212 DoMethod(o, AROSM_List_Clear);
214 entry = data->ld_EntryTables;
215 while (entry)
217 next = entry->le_Next;
218 FreeVec(entry);
219 entry = next;
222 if (data->ld_PointerArray)
223 FreeVec(data->ld_PointerArray);
225 if (data->ld_Pool)
226 DeletePool(data->ld_Pool);
228 DoSuperMethodA(cl, o, msg);
231 /*****************
232 ** List::Get() **
233 *****************/
235 IPTR AROSList__OM_GET(Class *cl, Object *o, struct opGet *msg)
237 IPTR retval = 1UL;
238 struct ListData *data;
240 data = INST_DATA(cl, o);
242 switch (msg->opg_AttrID)
244 case AROSA_List_Entries:
245 *(msg->opg_Storage) = (IPTR)data->ld_NumEntries;
246 break;
248 case AROSA_List_Active:
249 *(msg->opg_Storage) = (IPTR)data->ld_Active;
250 break;
252 default:
253 retval = DoSuperMethodA(cl, o, (Msg)msg);
254 break;
256 return (retval);
259 /********************
260 ** List::Insert() **
261 ********************/
262 ULONG AROSList__AROSM_List_Insert(Class *cl, Object *o, struct AROSP_List_Insert *msg)
264 struct ListData *data;
266 register ULONG items2insert;
267 register ULONG pos;
269 ULONG numinserted;
271 ULONG items_below_insertion;
274 data = INST_DATA(cl, o);
276 items2insert = CountItems(msg->ItemArray);
277 pos = msg->Position;
279 /* Special value ? */
280 if (pos < 0)
282 switch (pos)
284 case AROSV_List_Insert_Top:
285 pos = 0L;
286 break;
287 case AROSV_List_Insert_Bottom:
288 pos = data->ld_NumEntries;
289 break;
291 default:
292 pos = data->ld_NumEntries;
293 break;
295 } /* switch (pos) */
297 } /* if (pos < 0) */
299 else if (pos > data->ld_NumEntries)
301 pos = data->ld_NumEntries;
304 items_below_insertion = data->ld_NumEntries - pos;
306 /* To little space left ? */
307 if (items2insert > data->ld_NumAllocated - data->ld_NumEntries)
309 struct ListEntry **newptrarray;
311 newptrarray = AllocEntries(items2insert, data);
312 if (!newptrarray)
313 return (0UL);
315 /* Copy all old entries BEFORE the new ones, into the new array */
316 if (pos != AROSV_List_Insert_Top)
318 CopyMem( data->ld_PointerArray,
319 newptrarray,
320 UB(newptrarray[pos]) - UB(newptrarray[0]));
323 /* Now insert the entries themselves */
324 numinserted = InsertItems(msg->ItemArray, newptrarray, pos, data);
326 /* Copy all the entries BELOW the inserted value */
327 if (pos != data->ld_NumEntries)
329 CopyMem(&(data->ld_PointerArray[pos]),
330 &newptrarray[pos + numinserted],
331 UB(newptrarray[items_below_insertion] ) - UB(newptrarray[0]));
333 /* Free the old buffer */
334 FreeVec(data->ld_PointerArray);
336 data->ld_PointerArray = newptrarray;
339 else
342 /* Insert at end of array ? */
343 if (pos == data->ld_NumEntries)
346 numinserted = InsertItems(msg->ItemArray,
347 data->ld_PointerArray,
348 pos,
349 data
351 D(bug("lins: inserted %d entries at end of list\n", numinserted));
353 else
356 /* Insertion in the middle of the array.
357 We have to move the some items down so we can
358 to get space for inserting the items */
359 register ULONG i;
360 register struct ListEntry **ptr;
362 ptr = &(data->ld_PointerArray[data->ld_NumEntries - 1]);
363 for (i = items_below_insertion; i; i -- )
365 ptr[items2insert] = *ptr;
366 ptr --;
369 numinserted = InsertItems(msg->ItemArray, data->ld_PointerArray, pos, data);
370 if (numinserted < items2insert)
373 * Ouch ! Insertion of some (or all) items failed, and we have to move
374 * the below items up again
377 ULONG delta = items2insert - numinserted;
379 ptr = &(data->ld_PointerArray[pos + numinserted /* This is where the items got moved */]);
381 for (i = items_below_insertion; i; i --)
384 *ptr = ptr[delta];
385 ptr ++;
387 } /* for (number of items to move) */
389 } /* if (not all entries inserted successfully) */
391 } /* if (Insert at end of arry or in middle) */
393 } /* if (Enough entries left for insertion) */
397 /* "Refresh" pos of the active entry */
398 if (pos <= data->ld_Active && data->ld_Active != AROSV_List_Active_None)
400 SetActive(data->ld_Active + numinserted, data);
403 data->ld_NumEntries += numinserted;
406 return (numinserted);
409 /***************************
410 ** List::InsertSingle() **
411 ***************************/
412 IPTR AROSList__AROSM_List_InsertSingle(Class *cl, Object *o, struct AROSP_List_InsertSingle *msg)
415 APTR ptrarray[2];
416 struct AROSP_List_Insert insert_msg;
418 ptrarray[0] = msg->Item;
419 ptrarray[1] = NULL;
421 insert_msg.MethodID = AROSM_List_Insert;
422 insert_msg.ItemArray = ptrarray;
423 insert_msg.Position = msg->Position;
425 return (IPTR)AROSList__AROSM_List_Insert(cl, o, &insert_msg);
428 /*********************
429 ** List::Remove() **
430 *********************/
431 VOID AROSList__AROSM_List_Remove(Class *cl, Object *o, struct AROSP_List_Remove *msg)
435 struct ListData *data;
436 LONG pos;
437 LONG lastpos;
438 struct ListEntry **ptr;
440 data = INST_DATA(cl, o);
442 pos = msg->Position;
443 lastpos = data->ld_NumEntries - 1;
445 if (pos < 0) /* Special value ? */
447 switch (pos)
449 case AROSV_List_Remove_First:
450 pos = 0;
451 break;
453 case AROSV_List_Remove_Last:
454 pos = lastpos;
455 break;
457 default:
458 /* No meaning */
459 return;
460 } /* switch (pos) */
463 if (pos > lastpos)
465 /* Cannot remove a non-existing entry */
466 return;
470 /* Call destructhook for entry */
471 if (data->ld_DestructHook)
473 CallHookPkt(data->ld_DestructHook,
474 data->ld_Pool,
475 data->ld_PointerArray[pos]->le_Item);
477 /* Add item to freelist */
478 AddLEHead(data->ld_UnusedEntries, data->ld_PointerArray[pos]);
479 data->ld_NumEntries --;
481 /* "Refresh" pos of the active entry */
482 if ( pos <= data->ld_Active
483 && data->ld_Active != AROSV_List_Active_None
484 && data->ld_Active != 0)
486 SetActive( ((data->ld_NumEntries)
487 ? data->ld_Active - 1 : AROSV_List_Active_None),
488 data);
491 /* Skip the specialcase where we remove the last entry */
492 if (pos < lastpos)
494 register ULONG i;
496 ptr = &(data->ld_PointerArray[pos]);
498 /* We remove a entry in the middle of the array and must move
499 all lower items up to fill the gap */
501 for (i = lastpos - pos; i; i --)
503 *ptr = ptr[1];
504 ptr ++;
507 return;
510 /********************
511 ** List::Clear() **
512 ********************/
513 VOID AROSList__AROSM_List_Clear(Class *cl, Object *o, Msg msg)
515 register LONG pos;
516 struct ListData *data = INST_DATA(cl, o);
518 D(bug("List::Clear()\n"));
520 for (pos = 0; pos < data->ld_NumEntries; pos ++)
522 D(bug("\tClearing entry at pos %d\n", pos));
524 if (data->ld_DestructHook)
526 CallHookPkt(data->ld_DestructHook,
527 data->ld_Pool,
528 data->ld_PointerArray[pos]->le_Item);
531 D(bug("Addidng to freeentrylist\n"));
532 /* Add item to freelist */
533 AddLEHead(data->ld_UnusedEntries, data->ld_PointerArray[pos]);
536 data->ld_NumEntries = 0;
537 /* "Refresh" pos of the active entry */
538 SetActive(AROSV_List_Active_None, data);
540 return;
544 /*********************
545 ** List::Select() **
546 *********************/
547 VOID AROSList__AROSM_List_Select(Class *cl, Object *o, Msg msg)
549 /* We _could_ put the Select_All stuff together
550 with the singlemode but that would slow down singlemode a little */
551 #undef S
552 #define S(msg) ((struct AROSP_List_Select *)msg)
553 struct ListData *data = INST_DATA(cl, o);
555 if (S(msg)->Position != AROSV_List_Select_All)
557 struct ListEntry *le;
559 le = data->ld_PointerArray[S(msg)->Position];
561 switch (S(msg)->SelType)
563 case AROSV_List_Select_On:
564 le->le_Flags |= LEFLG_SELECTED;
565 break;
567 case AROSV_List_Select_Off:
568 le->le_Flags &= ~LEFLG_SELECTED;
569 break;
571 case AROSV_List_Select_Toggle:
572 le->le_Flags ^= LEFLG_SELECTED;
573 break;
575 case AROSV_List_Select_Ask:
576 *(S(msg)->State) = ((le->le_Flags & LEFLG_SELECTED) != 0);
577 break;
580 else
582 register LONG pos;
583 register struct ListEntry *le;
585 *(S(msg)->State) = 0;
587 for (pos = 0; pos < data->ld_NumEntries; pos ++)
589 le = data->ld_PointerArray[S(msg)->Position];
590 switch (S(msg)->SelType)
592 case AROSV_List_Select_On:
593 le->le_Flags |= LEFLG_SELECTED;
594 break;
596 case AROSV_List_Select_Off:
597 le->le_Flags &= ~LEFLG_SELECTED;
598 break;
600 case AROSV_List_Select_Toggle:
601 le->le_Flags ^= LEFLG_SELECTED;
602 break;
604 case AROSV_List_Select_Ask:
605 if (le->le_Flags & LEFLG_SELECTED)
607 *(S(msg)->State) += 1;
609 break;
616 /***************************
617 ** List::NextSelected() **
618 ***************************/
619 VOID AROSList__AROSM_List_NextSelected(Class *cl, Object *o, Msg msg)
621 #undef NS
622 #define NS(msg) ((struct AROSP_List_NextSelected *)msg)
624 struct ListData *data = INST_DATA(cl, o);
625 register LONG pos;
627 pos = *(NS(msg)->Position);
629 if (pos == AROSV_List_NextSelected_Start)
630 pos = 0;
632 for (; pos < data->ld_NumEntries; pos ++)
634 if (data->ld_PointerArray[pos]->le_Flags & LEFLG_SELECTED)
636 *(NS(msg)->Position) = pos;
637 return;
641 *(NS(msg)->Position) = AROSV_List_NextSelected_End;
645 /***********************
646 ** List::GetEntry() **
647 ***********************/
648 VOID AROSList__AROSM_List_GetEntry(Class *cl, Object *o, Msg msg)
650 #undef GE
651 #define GE(msg) ((struct AROSP_List_GetEntry *)msg)
653 struct ListData *data;
655 data = INST_DATA(cl, o);
657 if (GE(msg)->Position >= data->ld_NumEntries || GE(msg)->Position < 0)
658 *(GE(msg)->ItemPtr) = NULL;
659 else
660 *(GE(msg)->ItemPtr) = data->ld_PointerArray[GE(msg)->Position]->le_Item;