Taglists

From MorphOS Library

Revision as of 14:10, 8 October 2011 by Krashan (talk | contribs) (TAG_SKIP)

Grzegorz Kraszewski


This article in other languages: Polish


What Is a Taglist?

A taglist is an array of "key-value" pairs. The key is always a 32-bit integer number and is called a tag. The value also has a size of 32 bits. It may be an integer, or a pointer to any structure or object. Taglists are commonly used in the MorphOS API for passing a variable number of arguments, usually sets of attributes with their values. A few special key values are used for array termination, concatenation and item skipping. A set of functions in the utility.library may be used for taglist traversing, filtering, searching, copying etc.

Every pair in a taglist is a TagItem structure, defined in <utility/tagitem.h>:

struct TagItem
{
  ULONG ti_Tag;
  ULONG ti_Data;
};

To be self descriptive, every taglist, being just a plain C array, must have some kind of termination. It is very similar to the string null-termination idea. The termination is done with a TagItem having its ti_Tag field set to TAG_END (which happens to be defined as zero). The ti_Data value of the terminating TagItem is ignored, it is usually set to zero too. The illustration below shows a simple taglist:


Taglists1.png


This taglist may be created with the following code:

double x = 3.438872763e+17;
Object *obj = NewObject( /* ... */ );

struct TagItem mytaglist[] = {
  { Tag1, 2837 },
  { Tag2, (ULONG)&x },
  { Tag3, (ULONG)"The quick brown fox..." },
  { Tag4, (ULONG)obj },
  { TAG_END, 0 }
};


Passing Taglists to Functions

Building taglists as global or local variables is not very convenient. That is why almost every MorphOS API function getting a taglist as one of its arguments has two forms. The first one accepts a pointer to the taglist. The second one is a variadic args macro building the taglist on the program stack dynamically. Such function pairs are named according to one of the two conventions:

  1. SomeFunctionA() takes a pointer to a taglist, SomeFunction() builds the taglist dynamically.
  2. SomeFunctionTagList() takes a pointer to a taglist, SomeFunctionTags() builds the taglist dynamically.


Continuing the above example, one can pass the example taglist to SomeFunction() in two ways:

SomeFunctionTagList(mytaglist);
SomeFunctionTags(Tag1, 2837, Tag2, (ULONG)&x, Tag3, (ULONG)"The quick brown fox...", Tag4,
 (ULONG)obj, TAG_END);

Of course in the second case variable mytaglist need not be defined anywhere. Note that for every taglist-based function the taglist is the last argument. There may be some plain arguments before it. It is a common practice to omit ti_Data for the terminator (it is ignored anyway).

Special tags

Special tags are used to avoid copying large blocks of data when taglists are manipulated. As taglists are plain arrays, operations like removing or inserting elements or merging taglists involve copying their large fragments. Special tags allow for doing these operations by only changing a few tags. Of course this comes at a price. Taglists with special tags (other than TAG_END) may be only manipulated with a set of functions from utility.library. All these functions detect special tags and interpret them properly. It should be noted, that even if taglists are created by hand and do not contain special tags, such tags may appear later, when taglists are passed to system functions. It is therefore recommended to always use utility.library tools to manipulate taglists, especially the taglist iterator named NextTagItem().

TAG_END

I've mentioned this tag already, it works as a taglist terminator. Its value is 0.

TAG_IGNORE

This special tag is used to logically remove a tag item from a taglist without copying large blocks of data. When a tag is to be removed, it is replaced with TAG_IGNORE, tags after it need not to be moved. Any taglist processing function will ignore the tag and advance to the next one immediately.

Taglists 3.png

TAG_MORE

This tag is used for joining taglists. Joining of plain arrays would require counting their size, allocating memory area and copying all tagitems. It is much simplier with TAG_MORE. If one wants to append taglist B at the end of taglist A, he replaces the terminator of taglist A with TAG_MORE and sets the data field to the address of taglist B. Then, when any taglist manipulation function sees this special tag, it fetches the next tag from the address. In effect taglists are logically joined into one.

Taglists 2.png

TAG_SKIP

This rarely used tag is used to logically remove larger fragments from a taglist. When encountered, it directs the taglist iterator to skip a specified number of following tags. The number is specified in the data field of TAG_SKIP.


Taglists 4.png

Traversing Taglists With NextTagItem()