, , Appel d’API en CL

Nous utilisons de plus en plus les services SQL pour de nombreuses actions : accès aux *DTAQ, *DTAARA, travaux etc …

Par exemple, pour accéder au contenu d’une variable d’environnement, la vue QSYS2.ENVIRONMENT_VARIABLE_INFO est très simple à utiliser :

Dans un programme RPG, il est très simple d’effectuer une lecture SQL.

Mais dans certains cas, nous préférerons utiliser les APIs système : pour la performance, ou dans le CL ! En CL, il est possible d’exécuter une instruction SQL, mais pas de récupérer un result sets (en tout cas pas simplement et avec une bonne performance).

L’appel d’API depuis le CL ne pose pas de soucis, principalement depuis les évolutions permettant de maitriser l’allocation mémoire des variables (variables autonomes, basées sur un pointeur, ou basée sur une autre variable – équivalent OVERLAY du RPG) :

Maintenant, lorsque l’on utilise des API, il est (souvent) nécessaire de passer par des pointeurs, de façon explicite ou non. Par exemple, c’est le cas pour QUSRJOBI même si l’on a pas déclaré de pointeur dans notre programme CL :

En réalité, lors d’un appel de programme ou procédure, les paramètres sont transmis par défaut par référence : concrètement on passe un pointeur sur le début de la valeur, mais pas la valeur elle-même !

Il faut commencer à interpréter les prototypes des API en fonction du langage d’appel …

Le système étant écrit en C, certaines API utilisent la définition C d’une chaine de caractères : un pointeur sur le premier caractère, la fin de la chaîne étant marquée par le premier octet null !

En RPG, nous avons la fonction %str() qui permet de gérer ceci :

En CL, pas de fonction équivalent pour gérer cela.

Prenons par exemple l’API getEnv() (en fait une fonction de la bibliothèque standard C) :

Il faut fournir en entrée le nom de la variable d’environnement, au format C String, c’est à dire à terminaison nulle.

De même, la valeur de retour est un pointeur sur le début de la valeur. La fin se situe au premier octet null rencontré …

Voici un exemple d’appel :

Nous déclarons simplement une variable de type CHAR(1) initialisée à x’00’ :

DCL VAR(&SPC_INIT) TYPE(*CHAR) LEN(1) VALUE(X'00')

Cela nous sert à créer la valeur pour l’appel : chaine à terminaison nulle contenant le nom de la variable d’environnement recherchée (ici CLASSPATH) :

CHGVAR &ENVVAR ( 'CLASSPATH' *CAT &SPC_INIT )

Pour décoder la valeur de retour, il nous faut parcourir la valeur reçue jusqu’à trouver la terminaison nulle. On utilise simplement %SCAN pour trouver la position et redécouper :

CHGVAR VAR(&POSNULL) VALUE(%SCAN(&SPC_INIT &ENVVARVAL) - 1 )
CHGVAR &FINALVAL %SUBSTRING(&ENVVARVAL 1 &POSNULL)

Au final, très peu de code à ajouter, mais nécessite une compréhension de la documentation des APIs, des types de données dans les différents langages, et des mécanismes de transmission de paramètres !