Developpement 400 RPG COBOL | Mise à jour 03-2013 |
|
Cette page présente des modèles de programmes en RPG 3 et 4 et en Cobol. Il ne s'agit pas d'un cours sur ces langages, mais plutôt d'un squelette de programme mettant en oeuvre des sous-fichiers. A quelques différences près, ce modèle s'adapte aux différents langages. Pour le cobol, des programmes mettant en oeuvre le traitement XML, les dates et l'instruction INSPECT. |
L'exemple construit ici est très simplifié, tant au niveau de ses fonctionnalités que de ses données. Il est organisé autour de deux tables : une table de clients (TESTPF1) attachés à des responsables (TESTPF2). La clé des clients est composée de cinq champs, dont les deux premiers seulement nous importent ici : le code responsable et le code client. Le programme principal (TEST02) se présente ainsi :
Les deux programmes sont construits de manière analogue et présentent peu de différences dans le traitement des sous-fichiers, qu'ils soient statique ou dynamique. En Statique Les données sont lues intégralement et chargées dans le sous-fichier. Une demande de positionnement recharge le sous-fichier à partir de la clé demandée. Le sous-fichier est affiché à partir de la première page. En Dynamique Les données sont lues page par page et chargées dans le sous-fichier. Une demande de positionnement recharge le sous-fichier à partir de la clé demandée. Une demande de pagination avant charge la suite des données dans le sous-fichier. C'est cette dernière page qui est présentée à l'écran. Se pose alors la nécessité :
Pour les formats d'écran, le choix a été de séparer les indicateurs des champs de données et d'utiliser pour les touches de fonction les indicateurs spécifiques (*INKx en RPG, le n° de touche à 2 chiffres en Cobol). Abordons maintenant la spécificité du COBOL par rapport au RPG. Contrairement au RPG, Cobol nécessite de déclarer des buffers d'entrée et de sortie séparés pour chaque format d'écran. En effet, en FD les buffers se rédéfinissent les uns les autres et sont donc écrasés à chaque accès écran. En général un format possède des champs en entrée-sortie et des champs en sortie. Ces deux définitions sont donc différentes et génèrent des noms de buffers suffixés par I et O. En revanche, si un format n'a par exemple que des champs de sortie (écran de visualisation), la définition d'un buffer d'entrée vide provoque une erreur de compilation. Il ne faut dans ce cas sélectionner que la description de sortie. Ensuite, si un format n'a que des champs d'entrée-sortie, les buffers d'entrée et de sortie sont identiques et portent donc en commun le nom du format d'écran, sans suffixe; on se trouve alors devant une ambiguité de nom. Du fait de l'emploi de buffers séparés, chaque lecture d'écran doit être suivie d'un transfert immédiat des zones d'entrée dans les zones identiques de sortie (instructions MOVE CORRESPONDING). Enfin, un programme Cobol se termine par STOP RUN, alors qu'un programme appelé (nommé sous-programme) doit se terminer par EXIT PROGRAM pour ne pas arrêter l'ensemble.
Volontairement, le parallèle a été conservé entre les différents langages afin de pouvoir facilement les comparer. Il est cependant évident que chacun propose des facilités d'écriture propres, qu'il est souhaitable d'utiliser (variables locales en RPG 4, définition de champ en RPG 3 lors de l'utilisation et non en début de programme). Le traitement général est constitué d'une boucle qui, en fonction d'un code format, lance le traitement correspondant. Le programme repasse à chaque itération par cette boucle générale. Par exemple, si une erreur est détectée sur le format d'appel, la routine de traitement, informée de l'anomalie, se termine sans avoir modifié le code format. La boucle générale reprend alors la main et relance donc la même routine. En revanche, si un traitement est validé, celui-ci modifie le code format et rend la main à la boucle générale qui va s'orienter sur le nouveau traitement demandé. Ensuite, viennent les routines de traitement dont l'explication suit. INIT En RPG3, décrit les clés d'accès aux fichiers et les variables du programme et les initialise à 0 ou blanc selon leur nature. En RPG 4 free, initialise les variables décrites en début de programme, comme en Cobol. INIS1 Initialise le sous-fichier en l'effaçant puis lance le chargement des données. Le code format prend la valeur S01 qui forcera la boucle principale à traiter le sous-fichier. TRTS1 Affiche le sous-fichier et interprète la transaction :
Lit une ligne de sous-fichier et contrôle la validité de la saisie effectuée sur cette ligne. En cas d'erreur, la main est rendue à l'affichage du sous-fichier (TRTS1). Ensuite le traitement dépend du mode dans lequel on travaille :
Exécute le traitement d'une ligne de sous-fichier, selon le mode choisi :
Viennent ensuite des fonctions utilitaires. REMPS1 Repositionne le fichier à la dernière clé chargée, et le rang du sous-fichier à la dernière ligne écrite. Charge ensuite une page de données (en statique, limite=9999 lignes). A la fin du chargement, si le sous-fichier est vide, une ligne avec les champs à blanc est ajoutée. Un indicateur est nécessaire pour masquer tous les champs d'entrée de cette ligne. Positionne l'affichage du sous-fichier à l'endroit désiré : 1ere page pour un statique, dernière page chargée pour un dynamique. Stocke les valeurs de rang et de clé actuelles. En mode statique, les sauvegardes de clé et de rang sont bien sûr inutiles mais permettent de conserver une logique d'écriture unique pour tous les cas. LECS1 Lit la prochaine ligne modifiée du sous-fichier. TRTL1 Exploite une ligne de sous-fichier en fonction de l'option sélectionnée. La routine se termine systématiquement par une mise à jour de la ligne. En cas de succès de traitement de la ligne, le code option est remis à blanc. En cas d'échec, les indicateurs d'erreur sont mis en fonction et le sous-fichier positionné sur la page contenant l'anomalie. INIC1 Initialise la boucle de contrôle du sous-fichier (indicateur de lecture et format à traiter). INIS1 Initialise la boucle de validation du sous-fichier (indicateur de lecture et format à traiter). Les fonctions suivantes sont consacrées au format d'appel du premier programme. INIF1 Initialise les champs du format d'appel. Le code format devient F01, pour forcer la boucle principale à traiter ce format. TRTF1 Affiche le format et interprète la transaction :
Contrôle la validité des données du format. En cas d'erreur, les indicateurs attachés aux champs sont activés et l'indicateur général d'erreur est positionné. |
Cette fonction très simple permet d'analyser séquentiellement un fichier XML. Pour des besoins simples, cela peut convenir; sinon il vaut mieux se tourner vers d'autres outils, qui permettent de naviguer dans l'arborescence du document. L'instruction PARSE balaye séquentiellement le document entier, chargé dans une variable. A chaque élément trouvé (balise, attribut, valeur d'attribut, contenu de balise), un événement est déclenché, accompagné de la valeur de l'élément en question. Pour extraire une valeur, cette méthode est suffisante, à part qu'il faut avoir chargé intégralement le document dans une variable. Pour des traitements plus complexes, il faut gérer soi-même les imbrications de balises, sans pouvoir aller directement à l'endroit désiré. Le programme se contente de recevoir les événements et les valeurs associées. Un traitement réel doit tester la description des événements et déclencher le traitement adapté. Ci-dessous la liste du programme, suivie de la liste des événements détectés :
Dès qu'une anomalie est détectée (exemple : balise de fin manquante), un événement d'erreur est déclenché et met fin à l'analyse du fichier.
Ce programme exemple montre l'utilisation des fonctions de date : conversion et calculs. Les zones date sont définies grâce au mot-clé format, en lieu et place du classique picture. Un mouvement entre deux zones dates ne nécessite pas de conversion explicite, la conversion s'effectuant grâce au format de chacune des zones. Un mouvement entre zones de natures différentes nécessite de préciser le format de la zone qui n'est pas une date. La fonction de conversion est sans effet sur des zones non dates. Les principaux codes utilisables dans la définition des formats sont définis ci-après. Voir pour plus de détails la documentation de la clause FORMAT.
Petite explication de l'instruction inspect, destinée à réaliser des fonctions de scan de chaines de caractères. Il existe aussi l'api QCLSCAN.
Une autre syntaxe de Inspect permet de remplacer des caractères par d'autres. Hélas, la chaine de remplacement doit être aussi longue que la chaine remplacée. La méthode suivante permet d'insérer une sous-chaîne dans un texte à un endroit variable, marqué par un caractère spécial. Dans la phrase "Le solde de votre compte ($) devra nous être adressé ...", le $ identifie le montant à inscrire. Il suffit donc de :
|