Aller au contenu

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, %PARMS donne le nombre de paramètres reçus.
*OMIT
On peut passer *OMIT à la place d'une variable. La procédure teste %ADDR(param) <> *NULL avant 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, %PARMS compte les paramètres transmis ; avec *OMIT, %ADDR(paramètre) vaut *NULL s'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.