With YODL version 2.00 the old-style post-processor has ceased to exist. Also,
the tt(.YODLTAGSTART.) and tt(.YODLTAGEND.) symbols no longer appear in
tt(yodl)'s output. 

Instead, a system using an em(index) file was adopted. When converting
information, tt(yodl) produces an output file and an associated em(index)
file. The index file defines em(offsets) in the output file up to where
certain actions are to be performed. Each line in the index file contains the
required information of one em(directive) for tt(yodlpost). For example:
        verb(
    0 set extension man
    53 ignorews
    2112 verb on
    2166 verb off
    80007 ignorews
    80065 copy
    80065 mandone
        )
    Entries can be written into the index file using the tt(INTERNALINDEX)
builtin function. This function has one argument: the information following
the offset where it is called. So, there will be a tt(INTERNALINDEX(set
extension man)) in the macro definitions for this particular conversion
(obviously it is a tt(man) conversion. The particular tt(INTERNALINDEX) call
is found in the standard tt(man.yo) macro definition file). 

    When tt(yodlmacros) is called, it processes the directives on the tt(idx)
file in two steps:
    itemization(
    it() First, it reads all directives, and constructs a queue of actions to
perform. During this phase it solves all references to, e.g., labels
defined in the file(s) processed by tt(yodl). This queue is constructed by a
tt(PostQueue) object, during its construction phase. 

    Postprocessing is realized by a template-method design pattern-like
construction in C.

    The algorithm proceeds as follows:

    Each element of the index file is read, and its keyword (the word
following the offset) is determined. Then the 'construct' function associated
with that keyword is called. The `construct' functions return pointers to
HashItem elements, which areprocessed by storing them either into the the
symbol table or into the work-queue. The construct functions can use all
tt(PostQueue, New, Message String Args) and tt(File) functions. Which function
is actually called is determined in the file tt(yodlpost/data.c), where the
array tt(Task task[]) is initialized. tt(Task) structs have three elements:
        itemization(
        it() tt(char const *d_key) points to the name of the keyword that 
triggers the corresponding tt(Task) struct;
        it() tt(HashItem *(*d_constructor)(char const *key, char *rest))
points to the function that is called when the task struct is created.
        it() tt( void (*d_handler)(long offset, HashItem *item)) points to the
function that is called when the queue is processed.
        )

    it() Then, when all commands are available, the queued commands are
processed. For this, the appropriate 'handle' functions are called. 
    )

    For example, when the tt(INTERNALINDEX(htmllabel ...)) is specified, the
function tt(construct_label()) is called. This function receives a line line
        verb(
    432 label Overview
        )
    meaning that this label has been defined in offset 432 in the file
generated by tt(yodl). The tt(construct_label()) function now:
    itemization(
    it() Stores the current section number, the filecount and the
sectionnumber in a HashItem.
    it() Stores the hashitem inside its hash-table.
    )

    Then, when the queue is processed, a reference to this label may be
encountered. This is signalled by an tt(INTERNALINDEX(ref Overview)) call. In
this case the tt(construct_ref()) function doesn't have to do much. Here it is
the handler that's doing all the work: 
    itemization(
    it() First it looks up the label in the symbol table. The label should be
there, as a result of the earlier construction of the symbol table during the
tt(postqueue_construct()) call. 
    it() Then it copies the file written by tt(yodl) up to the offset
mentioned in the the tt(ref) command.
    it() Then (since we're talking about an html-specific reference) the
appropriate tt(<a href=...) command is inserted into the current output file.
    )

    When references are solved in text-files, the tt(INTERNALINDEX(txtref
...)) command is used. Here, tt(construct_ref()) can still be used, but a
specific tt(handle_txt_ref()) function is required. 

    New postprocessing labels can be constructed easily:
    itemization(
    it() Add an element to the array tt(Task task[]) in
tt(src/yodlpost/data.c). For example, add a line like:
        verb(
    {"verb",            construct_verb,         handle_verb},
        )
    it() Declare the functions in tt(yodlpost.h):
        verb(
    HashItem *construct_verb(char const *key, char *rest);
    void handle_verb(long offset, HashItem *item);
        )
    it() The tt(construct_verb()) function receives the key (e.g., tt(verb))
and any information that may be available beyond the key as a trimmed line
(not beginning or ending in white space). The construct function should return
a pointer to a hashitem, which can be constructed by
tt(hashitem_construct()). This function should be called with the following
arguments:
        itemization(
        it() tt(VOIDPTR);
        it() a pointer to some text to be stored as the hashitem's key (use an
empty string if nothing needs to be stored in a hashtable);
        it() A pointer to the information associated with the key (use 0 if no
information is used; use tt((void *)intValue) to store an tt(int) value. Note
that this is em(not) tt((void *)&intValue): it is the value of the variable
that is interpreted as a pointer here).
        it() The function that handles the destruction of the
value-information. Use tt(free) if some information was actually allocated and
must be freed. E.g.,)
        verb(
    hashitem_construct(VOIDPTR, "", new_str(rest), free);
        )
    Use tt(root_nop) if no allocation took place. E.g.,
        verb(
    hashitem_construct(VOIDPTR, "", (void *)s_lastLabelNr, root_nop);
        )
    Often the constructor doesn't have to do anything at all. In that case,
initialize the tt(Task) element with the existing tt(construct_nop)
function. E.g., 
        verb(
    {"drainws",         construct_nop,          handle_drain_ws},
        )
    it() The tt(handle_verb()) function is called when the file produced by
tt(yodl) is processed by tt(postqueue_process()). This happens immediately
after tt(postqueue_construct()). The handler is called with two arguments: 
        itemization(
        it() Its first argument is the offset where the tt(INTERNALINDEX) call
was generated. The handler should make sure that tt(yodl)'s output file is
processed up to this offset. Not any further. If a simple copy is required the
function tt(file_copy2offset()) is available. E.g.,
        verb(
    file_copy2offset(global.d_out, postqueue_istream(), offset);
        )
    Note its arguments: the output and input file pointers are available
through, respectively, tt(global.d_out) and tt(postqueue_istream()). 
        it() Its second argument is a pointer to the hashitem struct
originally created by the matching tt(construct...()) function. The handler
should em(not) free the information it receives. The function
tt(postqueue_process()) takes care of that. 
       )
    Examples of actual tt(construct...()) and tt(handle...()) functions can be
found in tt(src/yodlpost). 
    )




