Search code examples
cpascalrecords

Translate C union to pascal variant record


Help a n00b out!

I'm writing bindings for a C library and I came across union declaration / variant record. I tried to make it work but with no luck.

Original C code:

struct _PurpleConversation
{
    PurpleConversationType type;  
    PurpleAccount *account;       
    char *name;                 
    char *title;
    gboolean logging;
    GList *logs;                
    union
    {
        PurpleConvIm   *im;
        PurpleConvChat *chat;
        void *misc;
    } u;
    PurpleConversationUiOps *ui_ops;
    void *ui_data;
    GHashTable *data;
    PurpleConnectionFlags features;
    GList *message_history;
};

My translation:

TPurpleConversation = record
    convtype : TPurpleConversationType; 
    account: PPurpleAccount;
    name : PChar;
    title: PChar;
    logging: Boolean32;
    logs: PGlist;
    ui_ops: TPurpleConversationUiOps;
    ui_data : Pointer;
    data: PGHashTable;                      
    features : TPurpleMessageFlags;
    message_history : PGList;         

    case u : integer of
    0:(
        im: PPurpleConversationIm;          
        chat: PPurpleConversationChat; 
        misc: Pointer;
    );
end;

What I think is wrong with it:

  • First thing that is wrong with it is that the varaiant record is in a different location, but in Pascal it can only be placed in the end of the record.
  • Variant record is falsely declared.

I asked some help from the #fpc channel and the two possible variants they pointed out was to make two records (one with only the variant record in it) and second was to use this case statement. The last option should be most compatible.

I have no previous experience with this kind of statement in Pascal so can somebody please explain how would this work?

Thanks!


Solution

  • So I got it working with using Marco van de Voort's code and modifying it a little - maybe someone finds it helpful here.

    {$packrecords C}
    TPurpleConversation = record
        convtype : TPurpleConversationType; 
        account: PPurpleAccount;
        name : PChar;
        title: PChar;
        logging: GBoolean;
        logs: PGlist;
    
        case longint of
          0 : ( im : PPurpleConversationIm );
          1 : ( chat : PPurpleConversationChat );
          2 : ( misc : Pointer;
                ui_ops: TPurpleConversationUiOps;
                ui_data : Pointer;
                data: PGHashTable;                      
                features : TPurpleMessageFlags;
                message_history : PGList;         
            );
    end;
    

    What was done:

    • Added the byte alignment directive {$packrecords C}.
    • Removed the tag from variant record.

    This allowed me to proceed and use that object a function parameter etc. and all was well. But there are other binding problems that just are not worth the effort so I dumped the FreePascal for this project and started pushing it in C.

    Thanks for the help!