Instruction RPG full free · IBM i (AS/400) · Mots-clés de déclaration
OPTIONS
Options d'un paramètre de prototype
Précise comment un paramètre peut être transmis : facultatif (*NOPASS), omissible (*OMIT), de longueur variable (*VARSIZE), converti en chaîne terminée par un zéro (*STRING) ou nettoyé de ses blancs (*TRIM).
Syntaxe
param type options(*nopass);
param type options(*omit);
param type options(*varsize);
param pointer value options(*string : *trim);
param type options(*nopass : *omit);
*NOPASS- Le paramètre peut ne pas être fourni. Dans la procédure,
%PARMSdonne le nombre de paramètres reçus. *OMIT- On peut passer
*OMITà la place d'une variable. La procédure teste%ADDR(param) <> *NULLavant de l'utiliser. *VARSIZE- Le paramètre reçu peut être plus court que sa déclaration. La procédure doit connaître sa vraie longueur (autre paramètre, par exemple).
*STRING- Pour un paramètre pointeur passé par valeur : l'appelant donne un caractère, la procédure reçoit l'adresse d'une copie terminée par x'00' (chaîne C).
*TRIM- Avec
*STRING: retire les blancs à gauche et à droite avant la conversion. - Effet
- Aucun indicateur. Avec
*NOPASS,%PARMScompte les paramètres transmis ; avec*OMIT,%ADDR(paramètre)vaut*NULLs'il a été omis.
À quoi ça sert
Un même sous-programme sert souvent avec ou sans tous ses arguments : un taux de TVA par défaut, un code retour dont certains appelants n'ont pas besoin, un tampon de taille variable. OPTIONS décrit ces cas dans le prototype, que le compilateur contrôle ensuite à chaque appel.
Pour appeler une fonction C comme strlen, *STRING évite d'ajouter soi-même x'00' en fin de zone, et *TRIM les blancs qui l'entourent.
Exemple 1 : *NOPASS et *OMIT
**free
// OPTIONS(*NOPASS) et OPTIONS(*OMIT) : parametre facultatif, parametre qu'on peut omettre.
ctl-opt dftactgrp(*no) actgrp(*new);
dcl-pr majore packed(9:2);
montant packed(9:2) const;
taux packed(5:2) const options(*nopass);
end-pr;
dcl-pr diviser;
dividende packed(9:2) const;
diviseur packed(9:2) const;
reste packed(9:2) options(*omit);
end-pr;
dcl-s r packed(9:2);
dcl-s reste packed(9:2);
snd-msg 'Sans taux : ' + %char(majore(1000));
snd-msg 'Avec taux : ' + %char(majore(1000 : 5.5));
diviser(17 : 5 : reste);
snd-msg 'Reste demande : ' + %char(reste);
diviser(17 : 5 : *omit);
*inlr = *on;
dcl-proc majore;
dcl-pi *n packed(9:2);
montant packed(9:2) const;
taux packed(5:2) const options(*nopass);
end-pi;
dcl-s t packed(5:2) inz(20);
if %parms >= 2;
t = taux;
endif;
return montant * (1 + t / 100);
end-proc;
dcl-proc diviser;
dcl-pi *n;
dividende packed(9:2) const;
diviseur packed(9:2) const;
reste packed(9:2) options(*omit);
end-pi;
if %addr(reste) <> *null;
reste = %rem(%int(dividende) : %int(diviseur));
snd-msg 'Reste ecrit';
else;
snd-msg 'Reste omis';
endif;
end-proc;
Résultat réel, compilé et exécuté sur IBM i 7.5 :
Sans taux : 1200.00
Avec taux : 1055.00
Reste ecrit
Reste demande : 2.00
Reste omis
majore accepte un second paramètre facultatif : sans lui, le taux par défaut est 20 % (1200,00) ; avec 5,5, le résultat est 1055,00. diviser reçoit un reste que l'appelant peut omettre : la procédure l'écrit seulement si son adresse n'est pas nulle.
Exemple 2 : *VARSIZE, *STRING et *TRIM
**free
// *VARSIZE, *STRING et *TRIM : longueurs variables et chaines terminees par x'00'.
ctl-opt dftactgrp(*no) actgrp(*new);
dcl-pr remplir;
zone char(100) options(*varsize);
lng int(10) const;
end-pr;
dcl-pr longueur_c int(10) extproc('strlen');
texte pointer value options(*string : *trim);
end-pr;
dcl-s court char(8);
dcl-s long char(30);
dcl-s nom char(20) inz(' Dupont SA');
remplir(court : %size(court));
remplir(long : %size(long));
snd-msg 'court : [' + court + ']';
snd-msg 'long : [' + long + ']';
snd-msg 'strlen avec *STRING et *TRIM : ' + %char(longueur_c(nom));
snd-msg 'strlen d un litteral : ' + %char(longueur_c('Montpellier'));
*inlr = *on;
dcl-proc remplir;
dcl-pi *n;
zone char(100) options(*varsize);
lng int(10) const;
end-pi;
dcl-s i int(10);
for i = 1 to lng;
%subst(zone : i : 1) = '*';
endfor;
end-proc;
Résultat réel, compilé et exécuté sur IBM i 7.5 :
court : [********]
long : [******************************]
strlen avec *STRING et *TRIM : 9
strlen d un litteral : 11
La procédure remplir est déclarée avec char(100) mais reçoit une zone de 8 puis de 30 caractères, grâce à *varsize ; la longueur est passée à part. strlen est la fonction C qui compte jusqu'au x'00' : elle trouve 9 pour ' Dupont SA' (blancs retirés) et 11 pour le littéral.
Exemple 3 : Lire un *NOPASS non transmis
**free
// Piege : lire un parametre *NOPASS qui n'a pas ete transmis.
ctl-opt dftactgrp(*no) actgrp(*new);
dcl-pr majore packed(9:2);
montant packed(9:2) const;
taux packed(5:2) const options(*nopass);
end-pr;
snd-msg 'Debut';
snd-msg 'Sans taux : ' + %char(majore(1000));
snd-msg 'Avec taux : ' + %char(majore(1000 : 5.5));
*inlr = *on;
dcl-proc majore;
dcl-pi *n packed(9:2);
montant packed(9:2) const;
taux packed(5:2) const options(*nopass);
end-pi;
return montant * (1 + taux / 100);
end-proc;
Résultat réel, compilé et exécuté sur IBM i 7.5 :
Debut
Erreur : RNQ0202 - (C G D F) Appel à MAJORE terminé en erreur.
Le programme affiche « Debut », puis appelle majore(1000) sans le taux alors que la procédure lit taux sans contrôle. Le travail s'arrête sur RNQ0202 (MCH3601).
Le piège
Un paramètre *NOPASS non transmis ne doit jamais être lu sans %PARMS. Dans le troisième exemple, l'appel sans taux plante (RNQ0202, MCH3601). Plus insidieux : en inversant l'ordre des deux appels, nous avons obtenu 1055,00 sans erreur, c'est-à-dire que la procédure avait lu le taux 5,5 laissé en mémoire par l'appel précédent. Écrivez toujours if %parms >= 2; (ou %addr(param) <> *null pour *OMIT) avant d'utiliser le paramètre.