InEnglish

How to do polymorphism in C ?

Thursday, 31 October 2024
|
Écrit par
Grégory Soutadé

At work, I had to write a code architecture with types polymorphism in C language. The idea is very basic : one header with common functions and multiple backend implementations. At compile time, we decide which kind of implementation is taken. This can be achieved in a very elegant way using a not so much known C feature : forward definition.

First, a quick recap :

here is a declaration of a function (usually in a header):

int my_func(void); 

Here is a definition of a function (usually in a .c file):

int my_func(void) { return 4; }

This is the same for structures.

Good solution

When compiling, compiler checks that types match declaration, but it needs definition only when object is handled. So, we can create an opaque structure (lets say struct my_struct_s) that can have multiple implementations using its pointer version:

public_header.h

#ifndef _PUBLIC_HEADER_H_
#define _PUBLIC_HEADER_H_

/* Opaque type "my_struct_s" */
struct my_struct_s;
typedef struct my_struct_s* my_struct_t;

my_struct_t init(void);
void do_something(my_struct_t param);
void print_my_struct_t(my_struct_t param);
void delete(my_struct_t param);

my_struct_t init2(void);
void do_something2(my_struct_t param);
void print_my_struct_t2(my_struct_t param);
void delete2(my_struct_t param);

#endif

And two private implementations:

private.c

#include "stdlib.h"
#include "stdio.h"

#include "public_header.h"

/* Private implementation */
struct my_struct_s
{
    int member_i;
};

my_struct_t init(void)
{
    my_struct_t res;

    res = malloc(sizeof(*res));
    res->member_i = 0;

    return res;
}

void do_something(my_struct_t param)
{
    param->member_i++;
}

void print_my_struct_t(my_struct_t param)
{
    printf("I'm an integer with value %d\n",
           param->member_i);
}

void delete(my_struct_t param)
{
    free(param);
}

private2.c

#include "stdlib.h"
#include "stdio.h"

#include "public_header.h"

/* Private implementation */
struct my_struct_s
{
    char member_c;
};

my_struct_t init2(void)
{
    my_struct_t res;

    res = malloc(sizeof(*res));
    res->member_c = 'a';

    return res;
}

void do_something2(my_struct_t param)
{
    param->member_c++;
}

void print_my_struct_t2(my_struct_t param)
{
    printf("I'm a character with value '%c'\n",
           param->member_c);
}

void delete2(my_struct_t param)
{
    free(param);
}

In main.c

#include "public_header.h"

int main()
{
    my_struct_t var;

    var = init();
    do_something(var);
    print_my_struct_t(var);
    delete(var);

    var = init2();
    do_something2(var);
    print_my_struct_t2(var);
    delete2(var);

    return 0;
}

In this example, both implementations are present in output program. But, we can use only one implementation, selected at compile time, and thus have same function names in both private.c and private2.c.

This example works because my_struct_t is a pointer to struct my_struct_s. So, type is checked correctly, and it doesn't care about pointed value unless operation like increment, decrement or dereferencement is done on it. For example, in main.c :

struct my_struct_s var2;

Will generate an error:

error: storage size of ‘var2’ isn’t known

Bad solution

Another solution for pylomorphism is

typedef void* my_struct_t;

But, I do not recommend to write it, because in this case pointer type is not checked, void* is too generic and match all of them. This code compiles without warnings and can lead to type confusion error !

#include "stdio.h"
#include "public_header.h"

typedef void* my_struct_t2;

static void print_string(char* a)
{
    printf("Value of param '%s'\n", a);
}

int main()
{
    my_struct_t2 var;
    var = init();
    do_something(var);

    print_string(var);

    delete(var);

    return 0;
}

NB : In my examples, I use "stdio.h" only because "<" and ">" are removed by code coloration.

IWLA 0.7

Sunday, 17 March 2024
|
Écrit par
Grégory Soutadé

Capture d'écran IWLA

Here is the work done for version 0.7 of IWLA (Intelligent Web Log Analyzer witten in Python) since one year and a half :

Core

  • Awstats data updated (7.9)
  • Remove detection from awstats dataset for browser
  • Don't analyze referer for non viewed hits/pages
  • Remove all trailing slashs of URL before starting analyze
  • Improve page/hit detection
  • Main key for visits is now "remote_ip" and not "remote_addr"
  • Add IP type plugin to support IPv4 and IPv6
  • --display-only switch now takes an argument (month/year), analyze is not yet necessary
  • Add --disable-display option

Plugins

  • Geo IP plugin updated (use of ip-api.com)
  • Update robot detection
  • Display visitor IP is now a filter
  • Add subdomains plugin

HTML

  • Generate HTML part in dry run mode (but don't write it to disk)
  • Set lang value in generated HTML page
  • Bugfix: flags management for feeds display
  • New way to display global statistics : with links in months names instead of "Details" button

Config

  • Add no_referrer_domains list to defaut_conf for website that defines this policy
  • Add excluded domain option
  • Set count_hit_only_visitors to False by default

A demo instance (for forge.soutade.fr) is available here

Debian stock on Cubox-i, USB issue

Sunday, 25 February 2024
|
Écrit par
Grégory Soutadé

My backup server was off for a while now. Something broken in my Sheevaplug power supply. And, if I do regular backup of my data on laptop, this is not the case for my server, so it was urgent to find a solution. I first though to buy a Cubox-M which is more powerful, but it's 250$ ! Quite expensive for this kind of stuff ! So I bought a second hand Cubox-i for for only 30€. This is a clone of my current server. I had to install everything from scratch, so I follow Solid Run instructions to prepare my SDCard with UBoot (with a new 2022 release and the ability to read ext4 partitions !).

> sudo dd if=SPL of=/dev/sdX bs=1k seek=1 conv=sync
> sudo dd if=u-boot.img of=/dev/sdX bs=1k seek=69 conv=sync

Then, I wanted to try to install a Debian distribution in stock version (with "nothing" from SolidRun) for an easier maintenance.

My SDCard partitioning looks like (partitioned with gparted) :

Cubox SDCard partitioning

On the main partition, I downloaded generic netboot console install from Debian server (netboot.tar.gz) and uncompress all files in the main partition. But I think it's better to put all in a directory named boot. Then put it in my Cubox and start to install using serial console.

> screen /dev/ttyUSB0 115200

Everything went fine, except that the image is configured for old stable release. So, I have to migrate to stable one (and don't forgot to remove installation files !).

When all was installed, I tried to put a USB key, but nothing happened... USB seems to work :

> lsusb
Bus 002 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub

After looking for kernel logs for a while (and a bit despairs), I found the solution : Debian compile its kernel with only few drivers linked. Most of them are in modules (located in /lib/modules/kernelname). And the one missing is USB PHY driver phy-mxs-usb ! In my main server, I had it compiled because I use target imx6/7.

So, then simplest way to test is :

> sudo modprobe phy-mxs-usb

And for automatic loading at boot time :

> sudo echo phy-mxs-usb >> /etc/modules

I also added tun, dm-mod and dm-crypt.

Libgourou v0.8.4

Thursday, 18 January 2024
|
Écrit par
Grégory Soutadé

Reminder : Libgourou is an open source ADEPT protocol implementation (ePub DRM management from Adobe) that helps download ACSM files on Linux system (and remove DRM).

Just two little fixes after a user reported an issue downloading his ebook from Kobo. Unfortunately it doesn't fix his issue as it's more a problem with new cloudflare firewall setup by Kobo.

Changes :

  • Bugfix : Operator URL only written when the full certificate is retrieved
  • Raise an error for HTTP request with status != 200
  • Set up cookie jar file for each session
  • Fix for compilation in Android (strptime() format)

You can find source code and binaries in my forge

Libgourou v0.8.3

Sunday, 01 October 2023
|
Écrit par
Grégory Soutadé

Reminder : Libgourou is a free ADEPT protocol implementation (ePub DRM management from Adobe) that helps download ACSM files on Linux system (and remove DRM).

No revolution for version 0.8.3 but only a bug raised by J.M. and a little feature coming from this bug :

  • Bugfix : bad ID used for loaned files
  • Server is now notified (if desired) when downloading file & loan return. Can be disabled with --no-notify option

You can find source code and binaries in my forge