Le langage RPG et le BATCH
Les principes
Le langage RPG d’origine (il a beaucoup évolué depuis), est basé sur un mode de programmation par cartes perforées. IBM a commencé par faire des cartes perforées pour les recensements. Pendant une longue période, les programmes étaient écrits sur du papier, puis ensuite on les traduisait sur des cartes perforées, et enfin on compilait le programme en empilant les cartes, de préférence dans le bon ordre, dans un lecteur. Quand on écrit un programme en RPG, on hérite de ces cartes, chaque ligne de programme est d’ailleurs appelée carte. On commence tout programme par une carte H (header, pour les instructions de compilation et autres), puis viennent les cartes F (pour la déclaration des fichiers) et les cartes C (la partie programme). Depuis le RPG ILE il y a aussi les cartes D (déclaration des variables).
Compte tenu de cette façon de programmer, on comprend mieux les contraintes du langage. Les fonctions, les facteurs, les résultats ou les indicateurs doivent être positionnés à un endroit précis. Pour faciliter le travail du programmeur il y a aussi les indicateurs (booléens) *IN01 à *IN99 qui sont implicites à tout programme RPG. Pour utiliser un indicateur, il suffit de lui affecter une valeur "0" ou "1", à la suite de quoi on pourra tester cette valeur et faire ce qui est nécessaire. Il est parfois assez difficile de comprendre comment va réagir telle ligne de code quand elle commence par : N17 22N54. Parce que si on parle de *IN17, dans la ligne il se nomme 17, et, dans cette ligne si l’indicateur 17 est éteint (SETOFF), l’indicateur 22 allumé (SETON) et l’indicateur *IN54 = ’0’ (SETOFF ou MOVE ’0’ *IN54), l’instruction qui suit sera exécutée. Pour la compacité, on peut difficilement faire mieux, pour la compréhension c’est moins évident. Rassurez-vous, on programme de moins en moins de cette façon, mais comme sur AS/400 on finit toujours par tomber sur un programme qu’il faut impérativement modifier et qui date de 1992, il vaut mieux avoir une idée sur la question.
Avant le RPG ILE, la déclaration des variables se faisait au fil de l’eau, il suffisait de définir...
Le fichier des messages
Pratiquement tous les programmes interactifs envoient, à un moment ou un autre, un message à l’utilisateur afin de l’informer du déroulement des opérations. L’AS/400 utilise abondamment ce type de message informatif. Ces messages sont le plus souvent affichés en surbrillance sur la ligne 24, la dernière en bas de l’écran. Si l’on tape ADDLIBLE TBIBDTA, le message sera : "Bibliothèque TBIBDTA ajoutée à la *LIBL" ou bien "Bibliothèque TBUBDTA inconnue" si vous avez tapé un "U" à la place du "I".
Nous allons donc créer dans la bibliothèque TBIBDTA un fichier de messages FICMSG qui contiendra les messages adaptés à la situation. Au fur et à mesure de la programmation, ce fichier de messages sera enrichi.
Le premier message est entièrement paramétrable, le deuxième fixe, le troisième mixte et ainsi de suite. Le code &1 sera remplacé, lors de l’exécution, par la valeur envoyée par le programme, si aucune valeur n’est passée il y aura juste un blanc.
Examinons maintenant, le contenu du message en tapant 2 sur le MSG0004.
Le message de premier niveau s’affichera en bas de l’écran, le message de deuxième niveau sera affiché si l’on fait [F1] sur le message....
Le compteur
Dans le futur programme de création d’un nouvel employé, le choix de la création du nouveau matricule de l’employé s’est porté sur la création automatique par compteur. Le fichier compteur comporte les zones suivantes :
CODE du compteur 3A.
CPT1 compteur 1 6S
CPT2 compteur 2 10S
Les zones d’audit, date et heure de création et de modification.
Le programme comporte quatre paramètres : CODE, NUM, CPT1, CPT2.
Le paramètre CODE permet de choisir quel enregistrement sera concerné, la clé unique du fichier.
Le NUM permet de choisir quel compteur est utilisé .
CPT1 et CPT2 retournent, en alphanumérique, la valeur des deux compteurs après l’incrémentation de l’un ou l’autre.
Dans l’exemple, seul le deuxième compteur sera utilisé lors de la création du matricule, le premier pourrait être utilisé pour d’autres fonctions, compteur journalier, compteur d’années, dépassement du premier compteur.
Le programme est assez simple, il n’y a qu’un seul fichier en création ou en mise à jour.
Si l’enregistrement existe, le programme boucle tant que l’enregistrement n’est pas disponible, par exemple dans le cas où un autre utilisateur utilise le même code. Une fois l’enregistrement libéré...
Les explications
Étudions maintenant les diverses parties qui composent un programme RPG. En premier lieu les cartes déclaratives, ensuite le corps proprement dit du programme, les cartes C.
Dans cet exemple assez simple, il n’y a qu’une procédure et le corps du programme est linéaire, sans aucune boucle, si ce n’est celle d’attente de libération du fichier.
Dans tous les programmes nous n’utiliserons pas tous les types de cartes qui existent en RPG. La liste exhaustive est la suivante dans l’ordre où elles doivent se retrouver dans un programme.
H contrôle, F description de fichiers, E extension, L compteur de ligne, I entrée, C calcul, O sortie suivis le cas échéant de cartes qui commencent par "**" permettant d’initialiser ou d’effectuer certaines fonctions sur les fichiers. Pour en savoir plus, on pourra se référer à la documentation fournie par IBM sur son site.
1. Le HEADER
Les options permettent de faire varier la façon dont fonctionnera le programme. Dans ce cas, ainsi que dans tous les autres programmes les options seront les mêmes, le mode "invite" puis [F1] permet de voir toutes les options possibles avec leur mode d’emploi. Ces options sont utilisées dans des cas très pointus d’optimisation ou de fonctionnalités particulières.
H DEBUG DECEDIT('0,') DATEDIT(*DMY.)
DEBUG autorise la création d’un fichier DUMP en cas de plantage. DECEDIT(’0,’) précise la présentation des nombres, la virgule en tant que séparateur décimal, le zéro signifie qu’un nombre décimal s’écrira 0,82 (par défaut c’est .82). DATEEDIT(*DMY) permet de fixer le format de date utilisé (JJMMSSAA) dans le programme lors de l’utilisation des dates système.
Petit détail, ce n’est pas ici que l’on autorise ou non le débogage, mais lors de la compilation.
Petit conseil au passage, même si cela oblige à une conversion de format, éviter de compiler chaque programme avec le format de date qui semble lui convenir le mieux. Pour faciliter la maintenance il est préférable de s’en tenir à un standard quelconque et de ne jamais en bouger.
2. Les cartes F
Dès que l’on utilise...
Programme d’édition
On commence, enfin, à écrire un programme qui donnera un résultat tangible, c’est-à-dire une page imprimée.
1. Le PRTF
Les PRTF sont nommés le plus souvent comme suit, PGMF20PR, c’est à dire le nom du programme avec le suffixe PR, mais rien n’interdit de faire autrement.
Nous avons vu auparavant que la mise en page d’un PRTF (Print File) pouvait se faire par RLU. Il est tout aussi possible de créer le fichier directement dans SEU, d’autant que la convivialité de RLU laisse à désirer. Personnellement j’aime autant la saisie dans SEU.
0001.00 A R ENTETE
0002.00 A SKIPB(1)
0003.00 A SPACEB(1)
0004.00 A 2'Programme d''édition :'
0005.00 A ZPGM 10 23
0006.00 A 120'Page :'
0007.00 A ZPAG 4 0 127
0008.00 A EDTCDE(Z)
0009.00 A SPACEA(1)
Le format d’en-tête sera édité en haut de chaque nouvelle page, ainsi que le suivant qui imprime le libellé de chaque colonne.
Le mot-clé SKIPB, indique un saut de page avant l’impression de la page, le SPACEB met une ligne blanche.
Chaque zone est définie en fonction de son type, alphanumérique, numérique et de sa longueur. On doit préciser aussi sa position (23). Là encore, l’usage de la touche [F4] et [F1] sur chaque zone permet d’en savoir plus sur les possibilités.
Les "constantes" sont définies de la façon habituelle, avec la double QUOTE.
De toute façon, SEU signalera le manquement aux règles en mettant en inversion la ou les lignes fautives. Le résultat si on oublie la double QUOTE :
|
À la suite de chaque zone, on peut rajouter un mot-clé qui permet de formater la zone comme on le souhaite.
0011.00 A ZDATE 8 0 15
0012.00 A EDTWRD(' / / ')
Après quelques tâtonnements, il s’avère que c’est assez intuitif, on se doute bien comment sera éditée la zone date que l’on vient de définir.
La seule particularité de ce PRTF c’est que c’est du 2 en 1.
En effet, selon l’édition choisie dans le programme qui suit, on éditera le format COLON suivi d’autant de formats DETLIG, soit le format DETGEN.
Les zones définies dans le PRTF sont...
Un petit BATCH
Exceptionnellement ce source ne se retrouvera pas à la fin comme les autres.
Il faut dire que c’est un cas un peu particulier qui permet de voir comment utiliser les possibilités du RPG quand on a besoin d’un résultat assez simple.
Dans ce programme, contrairement à ce que l’on fait généralement, il n’y a pas de fichier d’impression externe.
On a besoin d’éditer une liste des employés, ce n’est qu’un outil de travail qui ne demande pas de mise en page particulière. On veut juste imprimer le contenu du fichier.
0001.00 H DEBUG DECEDIT('0,') DATEDIT(*DMY.)
0002.00 F*****************************************************
0003.00 F* *
0004.00 F* Edition simple *
0005.00 F* *
0006.00 F*****************************************************
0007.00 FFIC00P IF E DISK
0008.00 FQPRINT O F 132 PRINTER OFLIND(IN99)
0009.00 C* Listing clair et simple pas de paramètres
0010.00 C* Edition en tete
0011.00 C EXCEPT ENTETE
0012.00 C* Lecture du fichier, sans aucun classement
0013.00 C SETOFF 99
0014.00 C READ FIC00P 9070
0015.00 C *IN70 DOWEQ '0'
0016.00 C* Edition ligne
0017.00 C EXCEPT DETAIL
0018.00 C* Fin de page nouvel en tete
0019.00 C 99 EXCEPT ENTETE
0020.00 C 99 SETOFF 99
0021.00 C* On boucle jusqu'à fin de fichier
0022.00 C READ FIC00P 9070
0023.00 C ENDDO
0024.00 C SETON LR
0025.00 C* Le fichier de sortie d'impression...
Remarques sur les fichiers spoule
Il arrive fréquemment que l’on doive écrire un programme qui édite, par exemple, une seule fiche employé. Cela aurait pu être le cas dans l’édition étudiée précédemment. La raison, en général, est qu’il s’agit de quelque chose d’assez complexe, de nombreux fichiers sont ouverts, il y a une problématique de classement ou autre. En clair, le programme est assez complexe.
Lorsqu’il s’agit de n’éditer qu’une seule fiche, il n’y a aucun souci, en revanche si l’on doit imprimer une centaine de fiches tout se complique.
Soit on inclut dans le programme les deux options, mais encore faut-il le savoir dès le départ. Soit on fait un petit programme préalable qui appelle le programme d’édition autant de fois que nécessaire.
Si le spoule est routé directement sur une imprimante, l’utilisateur final remarquera assez peu la différence, il y aura tout au plus qu’une ou deux secondes de plus par document ce qui est négligeable sauf si l’on est celui qui attend deux minutes de plus devant l’imprimante.
Là où cela se complique un peu, c’est dans le cas où les documents ne sont pas routés et que l’on se retrouve avec une centaine de spoules à router...
Exercice
On va rester dans la simplicité, mais qui n’est pas insignifiante.
La direction a décidé de modifier les codes fonction des employés en fonction de la date d’entrée dans l’entreprise. La règle est la suivante : tout employé de niveau 100 sera passé au niveau 101 si son entrée en fonction est antérieure au 1er janvier 2005, les autres verront leur statut inchangé. On se rend compte dans ce programme de l’utilité du logique FIC003L dans le temps de traitement. Accessoirement il faudra créer le logique en question.
À la fin de chaque année, la direction a décidé d’octroyer une prime exceptionnelle à tous les employés de niveau 005, à condition qu’ils soient entrés en fonction depuis plus de cinq ans.
On va donc créer le fichier à envoyer à la paye. Ce fichier sera en fait sur une autre partition de la machine, voire sur un autre AS/400, on va donc créer un lien DDM pour la mise à jour puisque l’AS/400 de la paye n’est pas le même que celui sur lequel s’exécute le programme. Pour que tout se compile correctement, il faudra avoir sur la machine une copie du fichier et des logiques de la paye et encapsuler le programme par un CL, un exemple a été donné plus avant, qui active et désactive le lien...