added concrete implementations of putc(), getc(), getchar() and gets()
[tangerine.git] / rom / exec / lists.c
blobfb5eef9db21b13f9f61479997b837e2f97f8b831
1 /*
2 Copyright © 1995-2001, The AROS Development Team. All rights reserved.
4 #Description: @AROS.Exec.LISTS@
6 <chapter title="Exec Lists">
8 <p>Exec offers a standard way to create lists of structures. All you
9 need to do is to put <code>struct Node node;</code>
10 as the first
11 field into any structure you want to collect in a list. You can
12 then use the macro <code>NEWLIST()</code> to initialize a structure
13 of the type <code>struct List</code> and insert the nodes
14 with <code>AddHead()</code>, <code>AddTail()</code>,
15 <code>Enqueue()</code> or <code>Insert()</code>.<p>
17 <p>FIXME Explain other functions, how to use the macros,
18 give some example programs and explain how lists work.<p>
20 </chapter>
23 #include <string.h>
24 #include <exec/lists.h> /*#ALL*/
25 #include <proto/exec.h> /*#ALL*/
27 /*#AROS_LH********************************************************************
29 NAME */
30 void AddHead (
32 /* SYNOPSIS */
33 struct List * list, /*#A0
34 The list to insert the node into */
35 struct Node * node) /*#A1
36 This node is to be inserted */
38 /* LOCATION
39 Exec (40), BaseNotNecessary
41 FUNCTION
42 Insert Node <code>node</code> as the first node of the list.
44 RESULT
45 None.
47 NOTES
49 EXAMPLE
50 struct List * list;
51 struct Node * pred;
53 // Insert Node at top
54 AddHead (list, node);
56 BUGS
58 SEE ALSO
59 @AROS.Exec.LISTS@
61 INTERNALS
63 ******************************************************************************/
65 ASSERT_VALID_PTR(node);
66 ASSERT_VALID_PTR(list);
69 Make the node point to the old first node in the list and to the
70 head of the list.
72 node->ln_Succ = list->lh_Head;
73 node->ln_Pred = (struct Node *)&list->lh_Head;
76 New we come before the old first node which must now point to us
77 and the same applies to the pointer to-the-first-node in the
78 head of the list.
80 list->lh_Head->ln_Pred = node;
81 list->lh_Head = node;
82 } /* AddHead */
84 /*#AROS_LH********************************************************************
86 NAME */
87 void AddTail (
89 /* SYNOPSIS */
90 struct List * list, /*#A0
91 The list to insert the node into */
92 struct Node * node) /*#A1
93 This node is to be inserted */
95 /* LOCATION
96 Exec (41), BaseNotNecessary
98 FUNCTION
99 Insert Node node at the end of a list.
101 RESULT
103 NOTES
105 EXAMPLE
106 struct List * list;
107 struct Node * pred;
109 // Insert Node at end of the list
110 AddTail (list, node);
112 BUGS
114 SEE ALSO
115 @AROS.Exec.LISTS@
117 INTERNALS
119 ******************************************************************************/
121 // ASSERT_VALID_PTR(node); argh! TypeOfMem() doesn't know about the data segment!
122 ASSERT_VALID_PTR(list);
125 Make the node point to the head of the list. Our predecessor is the
126 previous last node of the list.
128 node->ln_Succ = (struct Node *)&list->lh_Tail;
129 node->ln_Pred = list->lh_TailPred;
132 Now we are the last now. Make the old last node point to us
133 and the pointer to the last node, too.
135 list->lh_TailPred->ln_Succ = node;
136 list->lh_TailPred = node;
137 } /* AddTail */
139 /*#AROS_LH********************************************************************
141 NAME */
142 void Enqueue (
144 /* SYNOPSIS */
145 struct List * list, /*#A0
146 Insert into this list. The list has to be in descending
147 order in respect to the field ln_Pri of all nodes. */
148 struct Node * node) /*#A1
149 This node is to be inserted. Note that this has to
150 be a complete node and not a MinNode ! */
152 /* LOCATION
153 Exec (45), BaseNotNecessary
155 FUNCTION
156 Sort a node into a list. The sort-key is the field
157 <code>node->ln_Pri</code>.
158 The node will be inserted into the list before the first node
159 with lower priority. This creates a FIFO queue for nodes with
160 the same priority.
162 RESULT
163 The new node will be inserted before nodes with lower
164 priority.
166 NOTES
167 The list has to be in descending order in respect to the field
168 <code>ln_Pri</code> of all nodes.
170 EXAMPLE
171 struct List * list;
172 struct Node * node;
174 node->ln_Pri = 5;
176 // Sort the node at the correct place into the list
177 Enqueue (list, node);
179 BUGS
181 SEE ALSO
182 @AROS.Exec.LISTS@
184 INTERNALS
186 ******************************************************************************/
188 struct Node * next;
190 assert (list);
191 assert (node);
193 /* Look through the list */
194 ForeachNode (list, next)
197 Look for the first node with a lower pri as the node
198 we have to insert into the list.
200 if (node->ln_Pri > next->ln_Pri)
201 break;
204 /* Insert the node before(!) next. The situation looks like this:
206 A<->next<->B *<-node->*
208 ie. next->ln_Pred points to A, A->ln_Succ points to next,
209 next->ln_Succ points to B, B->ln_Pred points to next.
210 ln_Succ and ln_Pred of node contain illegal pointers.
213 /* Let node point to A: A<-node */
214 node->ln_Pred = next->ln_Pred;
216 /* Let A point to node: A->node */
217 next->ln_Pred->ln_Succ = node;
219 /* Make next point to node: A<->node<-next<->B */
220 next->ln_Pred = node;
222 /* Make node point to next: A<->node->next<->B */
223 node->ln_Succ = next;
225 } /* Enqueue */
227 /*#AROS_LH********************************************************************
229 NAME */
230 struct Node * FindName (
232 /* SYNOPSIS */
233 struct List * list, /*#A0
234 Search this list. */
235 UBYTE * name) /*#A1
236 This is the name to look for. */
238 /* LOCATION
239 Exec (46), BaseNotNecessary
241 FUNCTION
242 Look for a node with a certain name in a list.
244 RESULT
246 NOTES
247 The search is case-sensitive, so "Hello" will not find a node
248 named "hello".
250 The list must contain complete Nodes and no MinNodes.
252 EXAMPLE
253 struct List * list;
254 struct Node * node;
256 // Look for a node with the name "Hello"
257 node = FindName (list, "Hello");
259 BUGS
261 SEE ALSO
262 @AROS.Exec.LISTS@
264 INTERNALS
266 ******************************************************************************/
268 struct Node * node;
270 assert (list);
271 assert (name);
273 /* Look through the list */
274 for (node=GetHead(list); node; node=GetSucc(node))
276 /* Only compare the names if this node has one. */
277 if(node->ln_Name)
279 /* Check the node. If we found it, stop. */
280 if (!strcmp (node->ln_Name, name))
281 break;
286 If we found a node, this will contain the pointer to it. If we
287 didn't, this will be <code>NULL</code> (either because the list was
288 empty or because we tried all nodes in the list)
290 return node;
291 } /* FindName */
293 /*#AROS_LH********************************************************************
295 NAME */
296 void Insert (
298 /* SYNOPSIS */
299 struct List * list, /*#A0
300 The list to insert the node into */
301 struct Node * node, /*#A1
302 This node is to be inserted */
303 struct Node * pred) /*#A2
304 Insert after this node. If this is NULL, node is inserted
305 as the first node (same as AddHead()) */
307 /* LOCATION
308 Exec (39), BaseNotNecessary
310 FUNCTION
311 Insert Node <code>node</code> after <code>pred</code> in list.
313 RESULT
315 NOTES
317 EXAMPLE
318 struct List * list;
319 struct Node * pred, * node;
321 // Insert Node node as second node in list
322 pred = GetHead (list);
323 Insert (list, node, pred);
325 BUGS
327 SEE ALSO
328 @AROS.Exec.LISTS@
330 INTERNALS
332 ******************************************************************************/
334 assert (node);
335 assert (list);
337 /* If we have a node to insert behind... */
338 if (pred)
340 /* Is this the last node in the list ? */
341 if (pred->ln_Succ) /* Normal node ? */
344 Our successor is the successor of the node we add ourselves
345 behind and our predecessor is just the node itself.
347 node->ln_Succ = pred->ln_Succ;
348 node->ln_Pred = pred;
351 We are the predecessor of the successor of our predecessor
352 (What ? blblblb... ;) and of our predecessor itself.
353 Note that here the sequence is quite important since
354 we need ln_Succ in the first expression and change it in
355 the second.
357 pred->ln_Succ->ln_Pred = node;
358 pred->ln_Succ = node;
360 else /* last node */
363 Add the node at the end of the list.
364 Make the node point to the head of the list. Our
365 predecessor is the previous last node of the list.
367 node->ln_Succ = (struct Node *)&list->lh_Tail;
368 node->ln_Pred = list->lh_TailPred;
371 Now we are the last now. Make the old last node point to us
372 and the pointer to the last node, too.
374 list->lh_TailPred->ln_Succ = node;
375 list->lh_TailPred = node;
378 else
381 add at the top of the list. I do not use <code>AddHead()</code>
382 here but write the code twice for two reasons: 1. The code is small
383 and therefore errors are unlikely and 2. If I would call
384 <code>AddHead()</code>, it would take almost as long to call the
385 function as the execution would take yielding 100% overhead.
387 node->ln_Succ = list->lh_Head;
388 node->ln_Pred = (struct Node *)&list->lh_Head;
389 list->lh_Head->ln_Pred = node;
390 list->lh_Head = node;
392 } /* Insert */
394 /*#AROS_LH********************************************************************
396 NAME */
397 struct Node * RemHead (
399 /* SYNOPSIS */
400 struct List * list) /*#A0
401 The list to remove the node from */
403 /* LOCATION
404 Exec (43), BaseNotNecessary
406 FUNCTION
407 Remove the first node from a list.
409 RESULT
410 The node that has been removed.
412 NOTES
414 EXAMPLE
415 struct List * list;
416 struct Node * head;
418 // Remove node and return it
419 head = RemHead (list);
421 BUGS
423 SEE ALSO
424 @AROS.Exec.LISTS@
426 INTERNALS
428 ******************************************************************************/
430 struct Node * node;
432 assert (list);
434 Unfortunately, there is no (quick) check that the node
435 is in a list
438 /* Get the address of the first node or NULL */
439 node = list->lh_Head->ln_Succ;
440 if (node)
442 node->ln_Pred = (struct Node *)list;
443 node = list->lh_Head;
444 list->lh_Head = node->ln_Succ;
447 /* Return the address or NULL */
448 return node;
449 } /* RemHead */
451 /*#AROS_LH********************************************************************
453 NAME */
454 void Remove (
456 /* SYNOPSIS */
457 struct Node * node) /*#A1
458 Remove this node from the list it is currently in. */
460 /* LOCATION
461 Exec (42), BaseNotNecessary
463 FUNCTION
464 Remove a node from a list.
466 RESULT
468 NOTES
469 There is no need to specify the list but the node must be in
470 a list !
472 EXAMPLE
473 struct Node * node;
475 // Remove node
476 Remove (node);
478 BUGS
480 SEE ALSO
481 @AROS.Exec.LISTS@
483 INTERNALS
485 ******************************************************************************/
487 assert (node);
489 Unfortunately, there is no (quick) check that the node
490 is in a list.
494 Just bend the pointers around the node, ie. we make our
495 predecessor point to our successor and vice versa
497 node->ln_Pred->ln_Succ = node->ln_Succ;
498 node->ln_Succ->ln_Pred = node->ln_Pred;
499 } /* Remove */
501 /*#AROS_LH********************************************************************
503 NAME */
504 struct Node * RemTail (
506 /* SYNOPSIS */
507 struct List * list) /*#A0
508 The list to remove the node from */
510 /* LOCATION
511 Exec (44), BaseNotNecessary
513 FUNCTION
514 Remove the last node from a list.
516 RESULT
517 The node that has been removed.
519 NOTES
521 EXAMPLE
522 struct List * list;
523 struct Node * tail;
525 // Remove node and return it
526 tail = RemTail (list);
528 BUGS
530 SEE ALSO
531 @AROS.Exec.LISTS@
533 INTERNALS
535 ******************************************************************************/
537 struct Node * node;
539 assert (list);
541 Unfortunately, there is no (quick) check that the node
542 is in a list.
545 /* Get the last node of the list */
546 if ( (node = GetTail (list)) )
548 /* normal code to remove a node if there is one */
549 node->ln_Pred->ln_Succ = node->ln_Succ;
550 node->ln_Succ->ln_Pred = node->ln_Pred;
553 /* return it's address or NULL if there was no node */
554 return node;
555 } /* RemTail */