The SysList container is derived from the System Object and acts as a list of pointers to arbitrary data. The list does not free the data when removed from the list. Each of the list entries points to the data. In this way, the list can organize any data.
typedef struct _SYS_LIST {
SYS_OBJ Obj; // standard object structure. must be first.
SYS_LIST_ENTRY Header;
} SYS_LIST;
typedef struct _SYS_LIST_ENTRY {
SYS_LIST_ENTRY *Prev;
SYS_LIST_ENTRY *Next;
VOID *Value;
} SYS_LIST_ENTRY;
Each entry points to the next and previous list entry OR the header's dummy entry. If it points to the dummy entry, it means it is either the first or the last list entry. Each entry also points to the data. That is, the list itself does not contain the data, only a pointer to the data.
- SysListInit - Initialize an empty list container.
- SysListEmpty - Free all list entries and reset to empty. Does not free data.
- SysListIsValid - Return if pointer points to a valid list container.
- SysListIsEmpty - Return whether list contains any list entries.
- SysListAddTail - Add a new list entry for data after the last list entry.
- SysListRemoveTail - Remove last list entry and return pointer to data.
- SysListRemoveHead - Remove first list entry and return pointer to data.
- SysListGetNext - Iterate through a list container.
SysListInit(&l);
pl == SysNew(SysList);
if (pl == NULL) {
// error...
}
SYS_LIST *pl;
if (!SysListAddTail (pl, p)) {
// error...
}
SysListEmpty(pl);
while (!SysListIsEmpty(pl)) {
free (SysListRemoveTail(pl));
}
SYS_LIST_POS pos;
VOID *p;
for (pos = NULL; SysListGetNext (pl, &pos, &p); ) {
// ... do something with p ...
}
The SysListO container is derived from SysList. But, instead of pointers to arbitrary data, the list contains system objects. When adding objects to the list, a copy is made of the specified object and when delete list entries, the object is deleted. Any object derived from SysObj can be in the list.
The SysListO is a simple, repurposed version of SysList. So, it doesn't need much more than a typedef and a few new library functions that talk about SysObj instead of VOID *. For example:
typedef SYS_LIST SYS_LIST_O;
And here's an example of a function prototype that uses SYS_OBJ instead of VOID *:
BOOLEAN
SysListOGetNext (
IN CONST SYS_LIST_O *p,
IN OUT SYS_LIST_POS *Pos,
OUT SYS_OBJ **Value
);
Here are the functions provided by the library for object lists.
- SysListOInit - Initialize object list.
- SysListOEmpty - Empty an object list.
- SysListOAddTail - Add a copy of an object to the end of the list.
- SysListORemoveTail - Remove the last object from the list and return a pointer to it.
- SysListORemoveHead - Remove the first object from the list and return a pointer to it.
- SysListOGetNext - Iterate through all objects in the list, returning a pointer.
Conclusion
So this gives us a real container! Simple, non-invasive and powerful.
Next time, I will introduce how I use these in a real program as two new containers SysStrA (a dynamic ASCII string container) and SysListStrA (a list of ASCII strings) make their appearance in the command-line handling of my UEFI HII parser.
The full source code for the library will be available at the end of this blog series, but if you want more right now, you can see much of the code for SysList in the next section. SysListO is very similar.
The Nitty-Gritty Details
SysListInit - Initialize a List
SYS_LIST *
SysListInit (OUT SYS_LIST *p)
{
if (SysObjInit (
&p->Obj,
SYS_LIST_SIGNATURE,
sizeof (SYS_LIST),
(SYS_OBJ_INIT) SysListInit,
(SYS_OBJ_EMPTY) SysListEmpty,
NULL,
(SYS_OBJ_VALID) SysListIsValid,
NULL) == NULL) {
SYSINFO ("unable to initialize List container.\n");
return NULL;
}
p->Header.Prev = p->Header.Next = &p->Header;
p->Header.Value = 0;
return p;
}
SysListEmpty - Empty a List
SYS_LIST *
SysListEmpty (IN OUT SYS_LIST *p)
{
if (!SysIsValid (p)) {
SYSINFO ("unable to empty List container.");
return NULL;
}
while (!SysListIsEmpty (p)) { // remove all entries.
SysListRemoveHead (p);
}
return p; // return pointer to now-empty List container.
}
SysListIsValid - Check whether list is valid
BOOLEAN
SysListIsValid (IN CONST SYS_LIST *p)
{
if (!SysObjIsValid (&p->Obj, SYS_LIST_SIGNATURE, sizeof (SYS_LIST))) {
SYSINFO ("invalid List container.\n");
return FALSE;
}
return TRUE;
}
SysListIsValid (IN CONST SYS_LIST *p)
{
if (!SysObjIsValid (&p->Obj, SYS_LIST_SIGNATURE, sizeof (SYS_LIST))) {
SYSINFO ("invalid List container.\n");
return FALSE;
}
return TRUE;
}
SysListAddTail - Add a list entry to the end of the list
BOOLEAN
SysListAddTail (
IN OUT SYS_LIST *p,
IN VOID *v
)
{
SYS_LIST_ENTRY *e;
SysListAddTail (
IN OUT SYS_LIST *p,
IN VOID *v
)
{
SYS_LIST_ENTRY *e;
if (!SysListIsValid (p)) {
SYSINFO ("unable to add tail.\n");
return FALSE;
}
SYSINFO ("unable to add tail.\n");
return FALSE;
}
e = malloc (sizeof (SYS_LIST_ENTRY));
if (e == NULL) {
SYSINFO ("out of memory.\n");
return FALSE;
}
if (e == NULL) {
SYSINFO ("out of memory.\n");
return FALSE;
}
e->Prev = p->Header.Prev;
e->Next = &p->Header;
e->Value = v;
e->Next = &p->Header;
e->Value = v;
p->Header.Prev->Next = e;
p->Header.Prev = e;
return TRUE;
}
p->Header.Prev = e;
return TRUE;
}
SysListRemoveTail - Remove last list entry in the list
VOID *
SysListRemoveTail (IN OUT SYS_LIST *p)
{
SYS_LIST_ENTRY *e;
VOID *v;
if (!SysListIsValid (p)) {
SYSINFO ("unable to remove tail.\n");
return NULL;
}
if (SysListIsEmpty (p)) {
SYSERR ("list is empty. unable to remove List element.\n");
return NULL;
}
e = p->Header.Prev; // retrieve the tail entry.
p->Header.Prev->Next = e->Next; // unlink the tail entry.
p->Header.Prev = e->Prev;
v = e->Value; // retrieve the value from old tail entry.
free(e); // delete the old tail entry.
return v;
}
SysListGetNext - Iterate through list entries
BOOLEAN
SysListGetNext (
IN CONST SYS_LIST *p,
IN OUT SYS_LIST_POS *Pos,
OUT VOID **Value
)
{
SYS_LIST_ENTRY *pe;
if (!SysListIsValid (p)) {
SYSINFO ("unable to get next element.\n");
return FALSE;
}
if (Pos == NULL) {
SYSINFO ("invalid list position. unable to get next element\n");
return FALSE;
}
if (*Pos == NULL) {
*Pos = (SYS_LIST_POS) p->Header.Next;
}
pe = (SYS_LIST_ENTRY *)(*Pos);
if (pe->Next == &p->Header) {
*Pos = NULL;
} else {
*Pos = (SYS_LIST_POS)(pe->Next);
}
if (*Pos == NULL) {
*Value = NULL;
return FALSE;
}
*Value = pe->Value;
return TRUE;
}
No comments:
Post a Comment