Provided by: libprima-perl_1.28-1.2_amd64 bug

NAME

       Prima::internals - Prima internal architecture

DESCRIPTION

       This documents elucidates the internal structures of the Prima toolkit, its loading
       considerations, object and class representation and C coding style.

Bootstrap

   Initializing
       For a perl script, Prima is no more but an average module that uses DynaLoader. As 'use
       Prima' code gets executed, a bootstrap procedure boot_Prima() is called. This procedure
       initializes all internal structures and built-in Prima classes. It also initializes all
       system-dependent structures, calling window_subsystem_init(). After that point Prima
       module is ready to use. All wrapping code for built-in functionality that can be seen from
       perl is located into two modules - Prima::Const and Prima::Classes.

   Constants
       Prima defines lot of constants for different purposes ( e.g. colors, font styles etc).
       Prima does not follow perl naming conventions here, on the reason of simplicity.  It is (
       arguably ) easier to write cl::White rather than Prima::cl::White.  As perl constants are
       functions to be called once ( that means that a constant's value is not defined until it
       used first ), Prima registers these functions during boot_Prima stage. As soon as perl
       code tries to get a constant's value, an AUTOLOAD function is called, which is binded
       inside Prima::Const.  Constants are widely used both in C and perl code, and are defined
       in apricot.h in that way so perl constant definition comes along with C one.  As an
       example file event constants set is described here.

        apricot.h:
          #define FE(const_name) CONSTANT(fe,const_name)
          START_TABLE(fe,UV)
          #define feRead      1
          FE(Read)
          #define feWrite     2
          FE(Write)
          #define feException 4
          FE(Exception)
          END_TABLE(fe,UV)
          #undef FE

        Const.pm:
          package fe; *AUTOLOAD = \&Prima::Const::AUTOLOAD;

       This code creates a structure of UV's ( unsigned integers ) and a register_fe_constants()
       function, which should be called at boot_Prima stage. This way feRead becomes C analog to
       fe::Read in perl.

Classes and methods

   Virtual method tables
       Prima implementation of classes uses virtual method tables, or VMTs, in order to make the
       classes inheritable and their methods overrideable. The VMTs are usual C structs, that
       contain pointers to functions.  Set of these functions represents a class. This chapter is
       not about OO programming, you have to find a good book on it if you are not familiar with
       the OO concepts, but in short, because Prima is written in C, not in C++, it uses its own
       classes and objects implementation, so all object syntax is devised from scratch.

       Built-in classes already contain all information needed for method overloading, but when a
       new class is derived from existing one, new VMT is have to be created as well. The actual
       sub-classing is performed inside build_dynamic_vmt() and build_static_vmt().
       gimme_the_vmt() function creates new VMT instance on the fly and caches the result for
       every new class that is derived from Prima class.

   C to Perl and Perl to C calling routines
       Majority of Prima methods is written in C using XS perl routines, which represent a
       natural ( from a perl programmer's view ) way of C to Perl communication.  perlguts
       manpage describes these functions and macros.

       NB - Do not mix XS calls to xs language ( perlxs manpage) - the latter is a meta-language
       for simplification of coding tasks and is not used in Prima implementation.

       It was decided not to code every function with XS calls, but instead use special wrapper
       functions ( also called "thunks") for every function that is called from within perl.
       Thunks are generated automatically by gencls tool ( gencls manpage ), and typical Prima
       method consists of three functions, two of which are thunks.

       First function, say Class_init(char*), would initialize a class ( for example).  It is
       written fully in C, so in order to be called from perl code a registration step must be
       taken for a second function, Class_init_FROMPERL(), that would look like

          newXS( "Prima::Class::init", Class_init_FROMPERL, "Prima::Class");

       Class_init_FROMPERL() is a first thunk, that translates the parameters passed from perl to
       C and the result back from C function to perl.  This step is almost fully automatized, so
       one never bothers about writing XS code, the gencls utility creates the thunks code
       automatically.

       Many C methods are called from within Prima C code using VMTs, but it is possible to
       override these methods from perl code. The actions for such a situation when a function is
       called from C but is an overridden method therefore must be taken. On that occasion the
       third function Class_init_REDEFINED() is declared. Its task is a reverse from
       Class_init_FROMPERL() - it conveys all C parameters to perl and return values from a perl
       function back to C. This thunk is also generated automatically by gencls tool.

       As one can notice, only basic data types can be converted between C and perl, and at some
       point automated routines do not help. In such a situation data conversion code is written
       manually and is included into core C files.  In the class declaration files these methods
       are prepended with 'public' or 'weird' modifiers, when methods with no special data
       handling needs use 'method' or 'static' modifiers.

       NB - functions that are not allowed to be seen from perl have 'c_only' modifier, and
       therefore do not need thunk wrapping. These functions can nevertheless be overridden from
       C.

   Built-in classes
       Prima defines the following built-in classes: (in hierarchy order)

           Object
               Component
                       AbstractMenu
                               AccelTable
                               Menu
                               Popup
                       Clipboard
                       Drawable
                               DeviceBitmap
                               Printer
                               Image
                                       Icon
                       File
                       Timer
                       Widget
                               Application
                               Window

       These classes can be seen from perl with Prima:: prefix.  Along with these, Utils class is
       defined. Its only difference is that it cannot be used as a prototype for an object, and
       used merely as a package that binds functions.  Classes that are not intended to be an
       object prototype marked with 'package' prefix, when others are marked with 'object' (see
       prima-gencls manpage).

Objects

       This chapter deals only with Prima::Object descendants, pure perl objects are not of
       interest here, so the 'object' term is thereafter referenced to Prima::Object descendant
       object.  Prima employs blessed hashes for its objects.

   Creation
       All built-in object classes and their descendants can be used for creating objects with
       perl semantics. Perl objects are created by calling bless(), but it is not enough to
       create Prima objects. Every Prima::Object descendant class therefore is equipped with
       create() method, that allocates object instance and calls bless() itself. Parameters that
       come with create() call are formed into a hash and passed to init() method, that is also
       present on every object. Note the fact that although perl-coded init() returns the hash,
       it not seen in C code. This is a special consideration for the methods that have 'HV *
       profile' as a last parameter in their class declaration. The corresponding thunk copies
       the hash content back to perl stack, using parse_hv() and push_hv() functions.

       Objects can be created from perl by using following code example:

          $obj = Prima::SampleObject-> create(
              name  => "Sample",
              index => 10,
          );

       and from C:

          Handle obj;
          HV * profile = newHV();
          pset_c( name, "Sample");
          pset_i( index, 10);
          obj = Object_create("SampleObject", profile);
          sv_free(( SV*) profile);

       Convenience pset_XX macros assign a value of XX type to the hash key given as a first
       parameter, to a hash variable named profile. "pset_i" works with integers, "pset_c" - with
       strings, etc.

   Destruction
       As well as create() method, every object class has destroy() method.  Object can be
       destroyed either from perl

          $obj-> destroy

       or from C

          Object_destroy( obj);

       An object can be automatically destroyed when its reference count reaches 0. Note that the
       auto destruction would never happen if the object's reference count is not lowered after
       its creation. The code

          --SvREFCNT( SvRV( PAnyObject(object)-> mate));

       is required if the object is to be returned to perl.  If that code is not called, the
       object still could be destroyed explicitly, but its reference would still live, resulting
       in memory leak problem.

       For user code it is sufficient to overload done() and/or cleanup() methods, or just
       onDestroy notifications. It is highly recommended to avoid overloading destroy method,
       since it can be called in re-entrant fashion. When overloading done(), be prepared that it
       may be called inside init(), and deal with the semi-initialized object.

   Data instance
       All object data after their creation represent an object instance.  All Prima objects are
       blessed hashes, and the hash key __CMATE__ holds a C pointer to a memory which is occupied
       by C data instance, or a "mate". It keeps all object variables and a pointer to VMT. Every
       object has its own copy of data instance, but the VMTs can be shared. In order to reach to
       C data instance gimme_the_mate() function is used. As a first parameter it accepts a
       scalar (SV*), which is expected to be a reference to a hash, and returns the C data
       instance if the scalar is a Prima object.

   Object life stages
       It was decided to divide object life stage in several steps.  Every stage is mirrored into
       PObject(self)-> stage integer variable, which can be one of csXXX constants.  Currently it
       has six:

       csConstructing
           Initial stage, is set until create() is finished.  Right after init() is completed,
           setup() method is called.

       csNormal
           After create() is finished and before destroy() started.  If an object is csNormal and
           csConstructing stage, Object_alive() result would be non-zero.

       csDestroying
           destroy() started. This stage includes calling of cleanup() and done() routines.

       csFrozen
           cleanup() started.

       csFinalizing
           done() started

       csDead
           Destroy finished

Coding techniques

   Accessing object data
       C coding has no specific conventions, except when a code is an object method. Object
       syntax for accessing object instance data is also fairly standard.  For example, accessing
       component's field called 'name' can be done in several ways:

        ((PComponent) self)-> name; // classic C
        PComponent(self)-> name;    // using PComponent() macro from apricot.h
        var-> name;                 // using local var() macro

       Object code could to be called also in several ways:

        (((PComponent) self)-> self)-> get_name( self); // classic C
        CComponent(self)-> get_name( self);             // using CComponent() macro from apricot.h
        my-> get_name( self);                           // using local my() macro

       This calling is preferred, comparing to direct call of Component_get_name(), primarily
       because get_name() is a method and can be overridden from user code.

   Calling perl code
       call_perl_indirect() function accepts object, its method name and parameters list with
       parameter format string. It has several wrappers for easier use, which are:

          call_perl( Handle self, char * method, char * format, ...)
          sv_call_perl( SV * object, char * method, char * format, ...)
          cv_call_perl( SV * object, SV * code_reference, char * format, ...)

       each character of format string represents a parameters type, and characters can be:

          'i' - integer
          's' - char *
          'n' - float
          'H' - Handle
          'S' - SV *
          'P' - Point
          'R' - Rect

       The format string can be prepended with '<' character, in which case SV * scalar ( always
       scalar, even if code returns nothing or array ) value is returned. The caller is
       responsible for freeing the return value.

   Exceptions
       As descriped in perlguts manpage, G_EVAL flag is used in perl_call_sv() and
       perl_call_method() to indicate that an eventual exception should never be propagated
       automatically.  The caller checks if the exception was taken place by evaluating

               SvTRUE( GvSV( PL_errgv))

       statement. It is guaranteed to be false if there was no exception condition. But in some
       situations, namely, when no perl_call_* functions are called or error value is already
       assigned before calling code, there is a wrapping technique that keeps previous error
       message and looks like:

           dG_EVAL_ARGS;                       // define arguments
           ....
           OPEN_G_EVAL;                        // open brackets
           // call code
           perl_call_method( ... | G_EVAL);    // G_EVAL is necessary
           if ( SvTRUE( GvSV( PL_errgv)) {
               CLOSE_G_EVAL;                   // close brackets
               croak( SvPV_nolen( GvSV( PL_errgv)));// propagate exception
               // no code is executed after croak
           }
           CLOSE_G_EVAL;                       // close brackets
           ...

       This technique provides workaround to a "false alarm" situation, if SvTRUE( GvSV(
       PL_errgv)) is true before perl_call_method().

   Object protection
       After the object destroy stage is completed, it is possible that object's data instance is
       gone, and even simple stage check might cause segmentation fault.  To avoid this,
       bracketing functions called "protect_object()" and "unprotect_object()" are used.
       protect_object() increments reference count to the object instance, thus delaying its
       freeing until decrementing unprotect_object() is called.

       All C code that references to an object must check for its stage after every routine that
       switches to perl code, because the object might be destroyed inside the call. Typical code
       example would be like:

          function( Handle object) {
               int stage;
               protect_object( object);

               // call some perl code
               perl_call_method( object, "test", ...);

               stage = PObject(object)-> stage;
               unprotect_object( object);
               if ( stage == csDead) return;

               // proceed with the object
          }

       Usual C code never checks for object stage before the call, because gimme_the_mate()
       function returns NULL if object's stage is csDead, and majority of Prima C code is
       prepended with this call, thus rejecting invalid references on early stage. If it is
       desired to get the C mate for objects that are in csDead stage, use
       "gimme_the_real_mate()" function instead.

   init
       Object's method init() is responsible for setting all its initial properties to the
       object, but all code that is executed inside init must be aware that the object's stage is
       csConstructing. init() consists of two parts: calling of ancestor's init() and setting
       properties. Examples are many in both C and perl code, but in short it looks like:

          void
          Class_init( Handle self, HV * profile)
          {
             inherited init( self, profile);
             my-> set_index( pget_i( index));
             my-> set_name( pget_c( name));
          }

       pget_XX macros call croak() if the profile key is not present into profile, but the
       mechanism guarantees that all keys that are listed in profile_default() are conveyed to
       init(). For explicit checking of key presence pexists() macro is used, and pdelete() is
       used for key deletion, although is it not recommended to use pdelete() inside init().

   Object creation and returning
       As described is previous sections, there are some precautions to be taken into account
       when an object is created inside C code.  A piece of real code from DeviceBitmap.c would
       serve as an example:

          static
          Handle xdup( Handle self, char * className)
          {
             Handle h;
             Point s;
             PDrawable i;

             // allocate a parameters hash
             HV * profile = newHV();

             // set all necessary arguments
             pset_H( owner,        var-> owner);
             pset_i( width,        var-> w);
             pset_i( height,       var-> h);
             pset_i( type,         var-> monochrome ? imBW : imRGB);

             // create object
             h = Object_create( className, profile);

             // free profile, do not need it anymore
             sv_free(( SV *) profile);

             i = ( PDrawable) h;
             s = i-> self-> get_size( h);
             i-> self-> begin_paint( h);
             i-> self-> put_image_indirect( h, self, 0, 0, 0, 0, s.x, s.y, s.x, s.y, ropCopyPut);
             i-> self-> end_paint( h);

             // decrement reference count
             --SvREFCNT( SvRV( i-> mate));
             return h;
          }

       Note that all code that would use this xdup(), have to increase and decrease object's
       reference count if some perl functions are to be executed before returning object to perl,
       otherwise it might be destroyed before its time.

              Handle x = xdup( self, "Prima::Image");
              ++SvREFCNT( SvRV( PAnyObject(x)-> mate)); // Code without these
              CImage( x)-> type( x, imbpp1);
              --SvREFCNT( SvRV( PAnyObject(x)-> mate)); // brackets is unsafe
              return x;

   Attaching objects
       The newly created object returned from C would be destroyed due perl's garbage cleaning
       mechanism right away, unless the object value would be assigned to a scalar, for example.

       Thus

           $c = Prima::Object-> create();

       and
           Prima::Object-> create;

       have different results. But for some classes, namely Widget ant its descendants, and also
       for Timer, AbstractMenu, Printer and Clipboard the code above would have same result - the
       objects would not be killed. That is because these objects call Component_attach() during
       init-stage, automatically increasing their reference count. Component_attach() and its
       reverse Component_detach() account list of objects, attributed to each other. Object can
       be attached to multiple objects, but cannot be attached more that once to another object.

   Notifications
       All Prima::Component descendants are equipped with the mechanism that allows multiple user
       callbacks routines to be called on different events. This mechanism is used heavily in
       event-driven programming. Component_notify() is used to call user notifications, and its
       format string has same format as accepted by perl_call_indirect().  The only difference
       that it always has to be prepended with '<s', - this way the call success flag is set, and
       first parameter have to be the name of the notification.

           Component_notify( self, "<sH", "Paint", self);
           Component_notify( self, "<sPii", "MouseDown", self, point, int, int);

       Notifications mechanism accounts the reference list, similar to attach-detach mechanism,
       because all notifications can be attributed to different objects. The membership in this
       list does not affect the reference counting.

   Multiple property setting
       Prima::Object method set() is designed to assign several properties at one time. Sometimes
       it is more convenient to write

          $c-> set( index => 10, name  => "Sample" );

       than to invoke several methods one by one. set() performs this calling itself, but for
       performance reasons it is possible to overload this method and code special conditions for
       multiple assignment. As an example, Prima::Image type conversion code is exemplified:

          void
          Image_set( Handle self, HV * profile)
          {
             ...
             if ( pexist( type))
             {
                int newType = pget_i( type);
                if ( !itype_supported( newType))
                   warn("RTC0100: Invalid image type requested (%08x) in Image::set_type",
                      newType);
                else
                   if ( !opt_InPaint)
                      my-> reset( self, newType, pexist( palette) ?
                         pget_sv( palette) : my->get_palette( self));
                pdelete( palette);
                pdelete( type);
             }
             ...
             inherited set ( self, profile);
          }

       If type conversion is performed along with palette change, some efficiency is gained by
       supplying both 'type' and 'palette' parameters at a time.  Moreover, because ordering of
       the fields is not determined by default ( although that be done by supplying '__ORDER__'
       hash key to set() }, it can easily be discovered that

           $image-> type( $a);
           $image-> palette( $b);

       and

           $image-> palette( $b);
           $image-> type( $a);

       produce different results. Therefore it might be only solution to code Class_set()
       explicitly.

       If it is desired to specify exact order how atomic properties have to be called, __ORDER__
       anonymous array have to be added to set() parameters.

          $image-> set(
             owner => $xxx,
             type  => 24,
             __ORDER__ => [qw( type owner)],
          );

API reference

   Variables
       primaObjects, PHash
           Hash with all prima objects, where keys are their data instances

       application, Handle
           Pointer to an application. There can be only one Application instance at a time, or
           none at all.

   Macros and functions
       dG_EVAL_ARGS
           Defines variable for $@ value storage

       OPEN_G_EVAL, CLOSE_G_EVAL
           Brackets for exception catching

       build_static_vmt
            Bool(void * vmt)

           Caches pre-built VMT for further use

       build_dynamic_vmt
            Bool( void * vmt, char * ancestorName, int ancestorVmtSize)

           Creates a subclass from vmt and caches result under ancestorName key

       gimme_the_vmt
            PVMT( const char *className);

           Returns VMT pointer associated with class by name.

       gimme_the_mate
            Handle( SV * perlObject)

           Returns a C pointer to an object, if perlObject is a reference to a Prima object.
           returns nilHandle if object's stage is csDead

       gimme_the_real_mate
            Handle( SV * perlObject)

           Returns a C pointer to an object, if perlObject is a reference to a Prima object. Same
           as "gimme_the_mate", but does not check for the object stage.

       alloc1
            alloc1(type)

           To be used instead (type*)(malloc(sizeof(type))

       allocn
            allocn(type,n)

           To be used instead (type*)(malloc((n)*sizeof(type))

       alloc1z
           Same as "alloc1" but fills the allocated memory with zeros

       allocnz
           Same as "allocn" but fills the allocated memory with zeros

       prima_mallocz
           Same as malloc() but fills the allocated memory with zeros

       prima_hash_create
            PHash(void)

           Creates an empty hash

       prima_hash_destroy
            void(PHash self, Bool killAll);

           Destroys a hash. If killAll is true, assumes that every value in the hash is a dynamic
           memory pointer and calls free() on each.

       prima_hash_fetch
            void*( PHash self, const void *key, int keyLen);

           Returns pointer to a value, if found, nil otherwise

       prima_hash_delete
            void*( PHash self, const void *key, int keyLen, Bool kill);

           Deletes hash key and returns associated value.  if kill is true, calls free() on the
           value and returns nil.

       prima_hash_store
            void( PHash self, const void *key, int keyLen, void *val);

           Stores new value into hash. If the key is already present, old value is overwritten.

       prima_hash_count
            int(PHash self)

           Returns number of keys in the hash

       prima_hash_first_that
            void * ( PHash self, void *action, void *params, int *pKeyLen, void **pKey);

           Enumerates all hash entries, calling action procedure on each.  If the action
           procedure returns true, enumeration stops and the last processed value is returned.
           Otherwise nil is returned. action have to be function declared as

            Bool action_callback( void * value, int keyLen, void * key, void * params);

           params is a pointer to an arbitrary user data

       kind_of
            Bool( Handle object, void *cls);

           Returns true, if the object is an exemplar of class cls or its descendant

       PERL_CALL_METHOD, PERL_CALL_PV
           To be used instead of perl_call_method and perl_call_pv, described in perlguts
           manpage. These functions aliased to a code with the workaround of perl bug which
           emerges when G_EVAL flag is combined with G_SCALAR.

       eval
            SV *( char *string)

           Simplified perl_eval_pv() call.

       sv_query_method
            CV * ( SV * object, char *methodName, Bool cacheIt);

           Returns perl pointer to a method searched by a scalar and a name If cacheIt true,
           caches the hierarchy traverse result for a speedup.

       query_method
            CV * ( Handle object, char *methodName, Bool cacheIt);

           Returns perl pointer to a method searched by an object and a name If cacheIt true,
           caches the hierarchy traverse result for a speedup.

       call_perl_indirect
            SV * ( Handle self, char *subName, const char *format, Bool cdecl,
                   Bool coderef, va_list params);

           Core function for calling Prima methods. Is used by the following three functions, but
           is never called directly. Format is described in "Calling perl code" section.

       call_perl
            SV * ( Handle self, char *subName, const char *format, ...);

           Calls method of an object pointer by a Handle

       sv_call_perl
            SV * ( SV * mate, char *subName, const char *format, ...);

           Calls method of an object pointed by a SV*

       cv_call_perl
            SV * ( SV * mate, Sv * coderef, const char *format, ...);

           Calls arbitrary perl code with mate as first parameter.  Used in notifications
           mechanism.

       Object_create
            Handle( char * className, HV * profile);

           Creates an exemplar of className class with parameters in profile. Never returns
           nilHandle, throws an exception instead.

       create_object
            void*( const char *objClass, const char *format, ...);

           Convenience wrapper to Object_create. Uses format specification that is described in
           "Calling perl code".

       create_instance
            Handle( const char * className)

           Convenience call to "Object_create" with parameters in hash 'profile'.

       Object_destroy
            void( Handle self);

           Destroys object. One of few Prima function that can be called in re-entrant fashion.

       Object_alive
            void( Handle self);

           Returns non-zero is object is alive, 0 otherwise.  In particular, current
           implementation returns 1 if object's stage is csNormal and 2 if it is csConstructing.
           Has virtually no use in C, only used in perl code.

       protect_object
            void( Handle obj);

           restricts object pointer from deletion after Object_destroy().  Can be called several
           times on an object.  Increments Object. protectCount.

       unprotect_object
            void( Handle obj);

           Frees object pointer after Object. protectCount hits zero.  Can be called several
           times on an object.

       parse_hv
            HV *( I32 ax, SV **sp, I32 items, SV **mark, int expected, const char *methodName);

           Transfers arguments in perl stack to a newly created HV and returns it.

       push_hv
            void ( I32 ax, SV **sp, I32 items, SV **mark, int callerReturns, HV *hv);

           Puts all hv contents back to perl stack.

       push_hv_for_REDEFINED
            SV **( SV **sp, HV *hv);

           Puts hv content as arguments to perl code to be called

       pop_hv_for_REDEFINED
            int ( SV **sp, int count, HV *hv, int shouldBe);

           Reads result of executed perl code and stores them into hv.

       pexist
            Bool(char*key)

           Return true if a key is present into hash 'profile'

       pdelete
            void(char*key)

           Deletes a key in hash 'profile'

       pget_sv, pget_i, pget_f, pget_c, pget_H, pget_B
            TYPE(char*key)

           Returns value of ( SV*, int, float, char*, Handle or Bool) that is associated to a key
           in hash 'profile'. Calls croak() if the key is not present.

       pset_sv, pset_i, pset_f, pset_c, pset_H
            void( char*key, TYPE value)

           Assigns a value to a key in hash 'profile' and increments reference count to a newly
           created scalar.

       pset_b
            void( char*key, void* data, int length)

           Assigns binary data to a key in hash 'profile' and increments reference count to a
           newly created scalar.

       pset_sv_noinc
            void(char* key, SV * sv)

           Assigns scalar value to a key  in hash 'profile' without reference count increment.

       duplicate_string
            char*( const char *)

           Returns copy of a string

       list_create
            void ( PList self, int size, int delta);

           Creates a list instance with a static List structure.

       plist_create
            PList( int size, int delta);

           Created list instance and returns newly allocated List structure.

       list_destroy
            void( PList self);

           Destroys list data.

       plist_destroy
            void ( PList self);

           Destroys list data and frees list instance.

       list_add
            int( PList self, Handle item);

           Adds new item into a list, returns its index or -1 on error.

       list_insert_at
            int ( PList self, Handle item, int pos);

           Inserts new item into a list at a given position, returns its position or -1 on error.

       list_at
            Handle ( PList self, int index);

           Returns items that is located at given index or nilHandle if the index is out of
           range.

       list_delete
            void( PList self, Handle item);

           Removes the item from list.

       list_delete_at
            void( PList self, int index);

           Removes the item located at given index from a list.

       list_delete_all
            void ( PList self, Bool kill);

           Removes all items from the list. If kill is true, calls free() on every item before.

       list_first_that
            int( PList self, void * action, void * params);

           Enumerates all list entries, calling action procedure on each.  If action returns
           true, enumeration stops and the index is returned.  Otherwise -1 is returned. action
           have to be a function declared as

            Bool action_callback( Handle item, void * params);

           params is a pointer to an arbitrary user data

       list_index_of
            int( PList self, Handle item);

           Returns index of an item, or -1 if the item is not in the list.

AUTHOR

       Dmitry Karasik, <dmitry@karasik.eu.org>.

SEE ALSO

       Prima