Brochure ILE RPG
Transcription
Brochure ILE RPG
1 Brochure ILE RPG Chapitre TABLE DES MATIERES Objectifs ; introduction. Pages 3 CHAPITRE I ILE RPG I.1) Structure du programme I1 IF.. ELSE.. ENDIF Structure SELECT.. WHEN.. OTHER.. ENDSL DOW LEAVE ITER ENDDO ; DOU DO LEAVE ITER ENDDO EXSR LEAVESR ENDSR CALLP Sous-Procédures (non utilise gén.). I.2) Carte F, carte D, Gestion base de données I2 Carte F, RENAME, SFILE, INFDS Accès, fichiers, Carte D et Data Structure, LIKE, OVERLAY données de CHAIN, READE, UPDATE, DELETE, CLEAR; *ALL; travail %EOF, SETLL I.3) Instructions de base EVAL(h) I3 ADD, SUB, MULT, DIV, +=, -=, *=, /= Instructions CLEAR, MOVE, MOVEL, CAT, EVAL ILE RPG Tableaux MOVEA T(I) XFOOT SORTA Tout sur les dates : carte D, ADDDUR, SUBDUR TEST(DE) test de la date Tableaux chargés à la compilation, CTDATA MOVE, MOVEL, TEST(n), *ALL’a’ EVAL alphanumérique, CAT BIF : %SUBST %LEN %TRIM API QCLSCAN CALLP. 4 5 7 9 10 11 12 13 15 18 19 21 22 24 26 27 28 29 30 31 CHAPITRE II Personnaliser (page suivante) 1 2 Chapitre Pages TABLE DES MATIERES CHAPITRE II Personnaliser II.1) Debogue II.2) Contrôle II.3) Préaffichage Sous-programmes II.4) Finitions II.5) Sous-fichier II.6) Edition II.6) Modif. COLHDG Comment deboguer un programme ILE RPG ? Comment ajouter un contrôle manuel dans une fiche FCH ? Comment préafficher un champ E/S en création fiche FCH ? Comment afficher les sous-programmes d’un modèle ? Comment visualiser ou effacer une finition générée ? Comment mixer finition générée et modification manuelle ? Comment charger le sous-fichier en total ? Comment forcer le chargement du sous-fichier ? Comment sont gérées les touches de fonction ? Comment est structuré un programme d’édition ? Comment paramétrer l’entête standard pour une société ? Comment s’effectuent les sauts de page à rupture et/ou à l’overflow ? Comment paramétrer l’overflow ? Comment modifier le COLHDG d’un PF et LF associés sans recompilation ? 33 35 39 41 43 44 45 47 47 49 50 2 3 Objectifs et Introduction Introduction : En informatique de gestion, l’expérience prouve qu’ il est possible d’écrire un programme en n’utilisant qu’une trentaine d’instructions de base environ. Les instructions peuvent de subdiviser en trois parties : 1. les instructions de structurations : le sous-programme, la structure conditionnelle et la structure répétitive. 2. les instructions de gestion de la base de données avec l’accès en lecture, l’écriture, la mise à jour… 3. les instructions de manipulation des données : les tables, les calculs, le peuplement des zones de travail… Nos générateurs génèrent des programmes complets à partir de modèles comme les programmes transactionnels, les éditions et les critères de sélection. Les développeurs doivent en connaître la structure globale afin de pouvoir personnaliser en fonction des particularités de chaque entreprise. Objectifs : A l’issue de cette formation ILE RPG pour nos générateurs, les stagiaires pourront réaliser des applications de gestion en ILE RPG clé en main, plusieurs fois plus vite, toutes les applications étant standardisées donc de qualité constante. Afin de garder un contrôle intellectuel sur les programmes, nous n’utilisons volontairement qu’un nombre limité d’instructions ILE RPG. Il existe aujourd’hui des centaines d’instructions sophistiquées ILE RPG. Le stagiaire pourra s’y reporter par la suite à mesure des besoins spécifiques de son entreprise en consultant les brochures IBM. Nos générateurs s’adressant aux sites qui ont souvent un fort existant en RPGII et RPGIII, aussi nous mettons parfois en regard les instructions RPGIII afin de relever les différences et d’y faciliter l’apprentissage. Il ne faut pas oublier non plus que le ILE RPG accepte également 80% de la syntaxe RPGIII. Première remarque : un membre source RPGIII se distingue d’un membre source ILE RPG par le type du membre source : RPGLE pour le ILE RPG. RPG pour le RPGIII La syntaxe est contrôlée lors de la saisie en fonction du type du membre source. 3 4 CHAPITRE I ILE RPG I.1) Structure En RPGIII, la syntaxe utilise le facteur1 et le facteur2. En ILE RPG, le facteur2 étendu permet d’exprimer la condition de façon très naturelle. Rappel RPGIII : IF …… ELSE …… ENDIF CL0N01N02N03Factor1+++OpcdeFactor2+++Result C Z1 IFEQ 'A' C Z2 ANDNE'B' C *IN12 ANDEQ'1' C ZA IFEQ ‘B’ C ZA OREQ ‘C’ C*...... C ELSE C*...... C ENDIF C ENDIF Voici les mêmes instructions en RPGIV : CL0N01Factor1+++++++Opcode&ExtFactor2++++++++ C IF Z1 = 'A' AND Z2 <> 'B' C AND *IN12 = *ON C AND (ZA = ‘B’ OR ZA = ‘C’) *....... C ELSE *....... C ENDIF Remarques : Le facteur2, qui exprime la condition du IF, est libre. Il peut être complété sur plusieurs lignes. Les conditions OR doivent souvent être mis entre parenthèses lorsqu’il y a également des AND car le AND est prioritaire sur le OR. Exemple : …AND (ZA = ‘B’ OR ZA = ‘D’) L’expression s’écrit exactement comme on l’écrirait au stylo sur une feuille de papier libre. La syntaxe est donc naturelle. Comme en RPGIII et contrairement au langage CL, il n’y a qu’un seul ENDIF avec ou sans le ELSE. Cette structure traite donc la condition avec la condition inverse si le ELSE est présent. Notez : *IN12 est l’indicateur 12 qui servira par exemple dans un DSPF au niveau zone pour activer un attribut d’affichage. *IN12 = ‘1’ est équivalent à *IN12 = *ON ou simplement *IN12. L’inverse étant *IN12 = ‘0’ ou *IN12 = OFF ou NOT(*IN12). *ON et *OFF sont des mots clés réservés équivalents à ‘1’ et ‘0’. *ON et *OFF peuvent s’employer avec toute variable de travail alphanumérique de 1 de long. 4 5 CHAPITRE I ILE RPG I.1) structure SELECT WHEN …. WHEN …. OTHER …. ENDSL WHEN est une instruction de structuration qu’il faut absolument maîtriser en ILE RPG. (en fait cette instruction est puissante, lisible et simple). WHEN peut remplacer simplement toutes les imbrications les plus complexes qui nécessiteraient des if then else imbriqués les uns dans les autres. Par exemple, l’algorithme suivant, fonction étant la touche de fonction : Si fonction = F06 | aller sous-programme SRWrkRcd Sinon | Si fonction = F04 | | aller sous-programme SRF04 | Sinon | | Si fonction = F12 | | | ……….. etc….. Peut être avantageusement représenté en ILE RPG avec la structure WHEN (remplace également ELSEIF): C* C C* C* C C C* C* C C C* C C C* C* C C C* C* C C C C* C* C C C C* C SELECT F06 créer F03 F04 F12 : WHEN EXSR KeyPress = F06 AND *IN01 SRWrkRcd : WHEN ……….. KeyPress = F03 WHEN EXSR KeyPress = F04 SRF04 WHEN KeyPress = F12 : : ………. ROLLUP : WHEN KeyPress = RollUp ………. OTHER Fonction invalide : EVAL WMsgId = 'FNC0001' EVAL WMsgF = WMsgFSys CALL 'WSNDMSG' WSndMsg ENDSL 5 6 CHAPITRE I ILE RPG I.1) structure (suite) SELECT WHEN …. WHEN …. OTHER …. ENDSL Dans cet exemple, lorsqu’une condition est remplie, par exemple si KeyPress = F04, les instructions correspondantes sont exécutées et l’instruction suivante sera inconditionnellement celle qui suit le ENDSL, même si la valeur de KeyPress a évolué lors de l’exécution des instructions du sous-programme SRF04 et a pris entre temps la valeur F12. Nous remarquons que l’emplacement des WHEN est très important car la première condition remplie sera exécutée et ensuite le traitement se poursuivra systématiquement après l’instruction ENDSL. Il faut donc construire une hiérarchie de WHEN… De ce fait, les conditions des WHEN qui suivent peuvent parfois être singulièrement simplifiées relativement aux conditions qui précèdent. Il faut considérer que la structure agit comme un filtre du haut vers le bas et construire la hiérarchie en conséquence. Si aucune condition est remplie et si OTHER est présent, les instructions qui suivent OTHER seront exécutées. Dans notre exemple, nous aurons alors un message d’erreur indiquant que la valeur de la fonction KeyPress est invalide. Nous verrons dans d’autres chapitres le traitement des erreurs, l’instruction EVAL ainsi que la variable KeyPress dans les programmes transactionnels. Notez que la condition peut être écrite au besoin sur plusieurs lignes. Rappel de l’instruction WHEN en RPGIII : C C C C*...... C C*...... C C*...... C C*...... C Z1 Z2 SELEC WHEQ 'A' ANDEQ'B' Z1 WHGE 'C' *IN12 WHEQ '1' OTHER ENDSL Equivalent en ILE RPG : C* C C C*…………….. C C*………………. C C C C*………… C SELECT WHEN Z1 = ‘A’ AND Z2 = ‘B’ WHEN Z1 >= ‘C’ WHEN ……….. OTHER *IN12 ENDSL Nous voyons bien que le ILE RPG est d’une syntaxe très proche d’ un algorithme qui serait écrit à la main sur une feuille de papier, ce qui facilite l’apprentissage et la lecture. Notez qu’il est plus naturel de représenter des conditions complexes avec des AND et des OR entre parenthèses. Notez que SELECT……..ENDSL qui délimitent la structure WHEN sont obligatoires (un oubli sera signalé de toute manière lors de la compilation). 6 7 CHAPITRE I ILE RPG I.1) Structure répétitive DOW …… LEAVE …… ITER …… ENDDO L’instruction de structuration DOW répète tant qu’une condition est remplie. Lorsqu’une instruction LEAVE est rencontrée, l’instruction suivante est celle qui suit le ENDDO. Lorsqu’une instruction ITER est rencontrée, l’instruction suivante est le ENDDO lui-même afin d’effectuer une autre itération tant que la condition est remplie. LEAVE et ITER peuvent simplifier grandement l’algorithme à l’intérieur de la boucle DOW. Ces 2 instructions n’ont pas les inconvénients de sauts inconditionnels dont ne sait pas, à première lecture, où sont placées les étiquettes de destination. LEAVE et ITER font donc partie intégrante de la structure répétitive elle-même. DOW est très utilisé en informatique de gestion associé à la lecture des enregistrements des fichiers. Lire le premier enregistrement Tant que non fin de fichier | ………. | lire l’enregistrement suivant Fin Tant que C C C*…………………………………. C C C C*…………………………………… C C READ DOW EXCLIENTR NOT %EOF(EXCLIENTL4) IF LEAVE ENDIF ERREUR = *ON READ ENDDO EXCLIENTR Dans cet exemple, le fichier EXCLIENTL4 est lu tant que non fin de fichier. ERREUR est une donnée de travail alphanumérique de 1 de long définie par le développeur et renseignée par le programme. La syntaxe suivante qui utilise l’indicateur de fin de fichier IN60 est strictement équivalente. Sont équivalents NOT(*IN60) ou *IN60 = ‘0’ : C C C*…………………………………. C C C C*…………………………………… C C C READ DOW EXCLIENTR *IN60 = *OFF IF LEAVE ENDIF ERREUR = ‘1’ READ ENDDO EXCLIENTR 60 60 7 8 CHAPITRE I ILE RPG I.1) Structure répétitive (suite) DOW …… LEAVE …… ITER …… ENDDO I.1) Structure répétitive DOU …… LEAVE …… ITER …… ENDDO Exemple en RPGIII : CL0N01N02N03Factor1+++OpcdeFactor2+++Result C Z1 DOWEQ'A' C Z2 ANDNE'B' C *IN12 ANDEQ'1' C*...... C ENDDO Equivalent en ILE RPG : CL0N01Factor1+++++++Opcode&ExtExtended-factor2++++ C DOW Z1 = 'A' AND C Z2 <> 'B' AND *IN12 *....... C ENDDO La structure DOU est un standard incontournable des langages actuels. Règle de la structure DOU : -) Un 1er passage dans la boucle au minimum est effectué inconditionnellement, sans tester la condition de la répétitive. -) Après le 1er passage, les passages suivants sont effectués jusqu’à ce que la condition soit remplie. Autrement dit, c’est la condition inverse du DOW. Exemple en RPGIII : CL0N01N02N03Factor1+++OpcdeFactor2+++Result C Z1 DOUNE'A' C Z2 ANDEQ'B' C *IN12 ANDEQ'0' C*...... C ENDDO Equivalent en ILE RPG : CL0N01Factor1+++++++Opcode&ExtExtended-factor2++++ C DOU Z1 <> 'A' AND C Z2 = 'B' AND C *IN12 = *OFF *....... C ENDDO Remarque : il est préférable de connaître également la syntaxe RPGIII, car elle est admise donc parfois utilisée dans les programmes en ILE RPG. Ainsi, la commande IBM CVTRPGSRC permet de convertir un membre source RPGIII en ILE RPG en gardant beaucoup de la syntaxe RPGIII. 8 9 CHAPITRE I ILE RPG I.1) Structure La structure d’incrémentation DO permet d’exécuter une série d’instructions incrémentation un nombre connu de fois. Notons qu’avec DO, ITER est très souvent utilisé. Cette structure se rencontre souvent dans les programmes ILE RPG pour gérer les tables. Nous verrons la syntaxe des tables ultérieurement. Ainsi : DO n CL0N01Factor1+++++++Opcode&ExtExtended-factor2++++ …… C EVAL I = 0 LEAVE C DO 10 C EVAL I = I + 1 …… C* ........... ITER C ENDDO …… ENDDO Est strictement équivalent à : CL0N01Factor1+++++++Opcode&ExtFactor2+++++++Result C DO 10 I C* ........... C ENDDO Syntaxe : facteur 2 : incrémentation Résultat : la variable de travail numérique I incrémentée. Eventuellement en facteur 1 : à partir de la valeur numérique. La valeur 1 est prise par défaut. Ici de 1 à 10 en incrémentant la variable I. Dans la pratique, la variable incrémentée sert souvent d’indice de table comme nous le verrons plus loin. Débat : Que penser de cette syntaxe ? Est-elle lisible ou non lisible ? Nous pensons qu’elle peut être très valable pour simplifier les cas les plus complexes. DO *HIVAL ENDDO C C*........ C C C C* C C C* C C*………………… C C*....... C DO *HIVAL SELECT WHEN LEAVE *IN03 = *ON WHEN LEAVE ZONEA = ZONEB OTHER ENDSL ENDDO Cette répétitive boucle à l’infini par définition même (*hival). Cette structure peut être utilisée avantageusement lorsque des conditions sont beaucoup trop complexes pour être cumulées dans un DOW par exemple. Il est plus simple dans ce cas de définir les les conditions de sortie de boucle avec LEAVE dans une structure WHEN. Si les conditions internes sont bien décrites la condition devient plus lisible. Pour utiliser cette structure, il faut admettre conceptuellement que LEAVE fait partie intégrante de la répétitive. 9 10 CHAPITRE I ILE RPG I.1) Structure Sous-programme EXSR Nom Nom BEGSR …… LEAVESR …… ENDSR C* C* C ………………. Chargement du sous-fichier page suivante : EXSR SRCharge C SRCharge BEGSR C CLEAR WCurLinWrt C* C* Ligne courante < nbre de lignes dans une page écran C DOW NOT %EOF(EXCLIENTL1) C AND WCurLinWrt < WSflPag C* C* Lectures détail ET préaffichages éventuels. C EXSR SRDtlRead C ADD 1 RRN C ADD 1 WCurLinWrt C CLEAR WOpt C MOVE *ZERO Z15 C MOVEA Z15 *IN(11) C WRITE WSFL C* C* EXCLIENTL1 Client par Pays C EXCLIEN001 READE(n) EXCLIENTR C* C ENDDO C C ENDSR Avantages de l’utilisation des sous-programmes : -) grande simplicité. -) isoler la structure d’un programme afin d’en avoir une vue d’ensemble sur une seule page. -) ranger les instructions correspondant à une fonction bien définie dans des tiroirs logiques. Ici, les instructions du chargement du sous-fichier. Le générateur et le développeur pourront ainsi retrouver et personnaliser facilement les instructions de ce sous-programme. Par exemple : ajouter un calcul niveau ligne du sous-fichier dans une zone de travail par exemple dans le sous-programme SRDtlRead avant l’instruction WRITE WSFL d’une ligne de sous-fichier. -) LEAVESR permet de terminer directement le sous-programme afin de simplifier l’algorithme. Notez que le saut inconditionnel est à bannir de manière générale car le lecteur ne sait pas à la 1ère lecture où l’étiquette est placée. LEAVESR ne présente pas cet inconvénient est donc admis. Inconvénient du sous-programme : -) pas de variable locale au sous-programme. -) pas de possibilité d’appel depuis un programme externe. La sous-procédure devrait en principe cumuler les avantages des sousprogrammes sans les inconvénients. Dans un but de facilité d’apprentissage d’un ILE RPG simple, assez proche du RPGIII, nos générateurs n’utilisent pas de sous-procédures sauf dans un cas ou deux particulier. 10 11 I.1) Structure Sous-procédure (Non utilisé) CHAPITRE I ILE RPG Dans un souci de facilité d’apprentissage, d’un ILE RPG qui ne serait pas trop éloigné du RPGIII, nos générateurs ne mettent pas en œuvre les sous-procédures. Cependant, voici brièvement un exemple : PR …… CALLP ……. PR D S i 65535A CONST OPTIONS(*VARSIZE) 65535A OPTIONS(*VARSIZE) 10I 0 CONST 5 ……………..………. callp CvtCaseEx1(szInput:szOutput:%size(szInput)) …………. B PI E D CvtCaseEx1 D InString D OutString D nLen P CvtCaseEx1 D CvtCaseEx1 D InString D OutString D nLen B PI D nDur D i S S C P CvtCaseEx1 E Export 65535A CONST OPTIONS(*VARSIZE) 65535A OPTIONS(*VARSIZE) 10I 0 CONST 10I 0 10 0 ………. return -) La sous-procédure doit être déclarée en début de programme en carte D PR avec les paramètres. -) Les paramètres de la sous-procédure doivent être décrits une seconde fois à la fin du programme B PI…..E -) L’instruction CALLP du corps de programme qui appelle la sousprocédure doit passer les paramètres décrits en PR, PI. CALLP NomSousProc(Parm1 :Parm2 :Parm3) -) Notons que les variables nDur et i sont des variables locales connues uniquement par la sous-procédure CvtCaseEx1. Ces variables locales peuvent tout à fait avoir un nom identique et des définitions différentes au niveau global, dans ce cas c’est la variable locale de même nom qui est prise à l’intérieur de la sous-procédure. Dans cet exemple, la variable i est connue en local en tant que variable numérique de 10 de long uniquement dans la sous-procédure CvtCaseEx1 et ailleurs en global comme étant une variable alphanumérique de 5 de long. Inconvénient : -) lourdeur de la syntaxe (déclarer les parms deux fois PR et PI). -) pas de possibilité de déclarer des fichiers en local alors que les données des fichiers représentent 90 à 100% des données en informatique de gestion. Avantage : -) variables de travail locales. -) possibilité d’appel d’une sous-procédure depuis un programme externe. Conclusion : -) indispensable dès que l’on fait de l’informatique scientifique complexe où les variables de travail sont très nombreuses car on évite ainsi des bogues vicieux en environnement de production. 11 12 I.2) Carte F Carte D Base de données CHAPITRE I ILE RPG Les cartes F sont décrites comme en RPGIII sauf pour les extensions. Dans cet exemple, le fichier à description : F* Client Exemples Fast FEXCLIENT UF A E K DISK Update avec Ajout Externe par Key (clés) Carte F Pour renommer un nom de format de fichier en carte F: FDBLFILE2 F IF E K DISK RENAME(DBLFILER:DBLFILE2R) RENAME Dans cet exemple, le format d’origine DBLFILER est renommé dans le programme DBLFILE2R. Mémo : dans le même sens qu’un OVRDBF. F* Ecran dspf : FABDSL2W CF E F F SFILE INFDS WORKSTN SFILE(WSFL:RRN) INFDS(DS_Display) SFILE : Pour le format du sous-fichier WSFL, la variable rang est RRN. Nous verrons que le sous-fichier est un fichier relatif. Typiquement, le programme doit incrémenter RRN, écrire les lignes du sous-fichier une à une, puis afficher la page par une écriture globale du format de contrôle associé. (n enregistrements du format WSFL) INFDS : la data structure de nom DS_Display va contenir des informations relative à l’écran. Nous verrons en détail la valeur de la variable KeyPress dans les transactionnels afin de récupérer la touche de fonction activée par l’utilisateur. 12 13 CHAPITRE I ILE RPG I.2) Carte F Carte D Single DVARETD1 DVARPAK1 DVARALPHA S S S 7S 3 6 2 60 S=Zone autonome ou Single. La variable VARETD1 est numérique étendue (S) de 7 dont 3 décimales La variable VARPAK1 est numérique packé de 6 dont 2 décimales. Packé par défaut si numérique (nombre de décimale <> blanc) La variable VARALPHA est alphanumérique. De 60 caractères (nombre de décimale = blanc) Dans la pratique, pour déclarer une donnée de travail, il suffit de recopier une carte D pour avoir le colonage et créer ainsi une nouvelle carte D. Rappel en RPGIII déclarer une donnée de travail VARDEC de longueur 7 dont 3 décimales en carte I : I LIKE 1 7 3VARDEC =============================================== DNOFAM …………………………………. DZFAM S 20 S LIKE(NOFAM) Ici la zone autonome ZFAM est de même type et de même longueur que NOFAM soit 20 de long alphanumérique. Note : il est également possible de faire référence à une zone de fichier. Avantage : En cas de changement de longueur d’une zone, il suffit de recompiler le programme pour modifier automatiquement la longueur les données de travail qui font référence à cette zone (qui peut provenir d’un fichier). Rappel en RPGIII nous avons l’équivalent en carte C mais NOFAM doit être une zone de fichier. C Constante *LIKE DEFN NOFAM ZFAM Nous reviendrons aux carte D pour les tables. ========================================== DVRAI C ‘Y’ Vrai est une constante qui prend la valeur ‘Y’. Nous pourrons avoir dans le programme le test suivant : C IF TEST = VRAI La condition est remplie si TEST a la valeur ‘Y’. 13 14 CHAPITRE I ILE RPG I.2) Carte F Carte D DS DSTRUCDS D DSZONE1 D DSZONE2 D DSZONE3 DS 256 LIKE(C1PAYS) LIKE(C1RAISON) 8 Le champ STRUCDS est une Data Structure alphanumérique de 256 de long. DSZONE1, DSZONE2 et DSZONE3 sont des sous-zone (car il n’y a pas S pour zone autonome Single mais blanc) Les sous-zones sont concaténées dans STRUCDS. Exemple : la sous-zone DSZONE2 débute en position 6 si DSZONE1 fait 5 de long. Donc les longueurs et les positions sont déduites automatiquement en fonction des longueurs des sous-zones précédentes. Par contre DSZONE3 est une donnée alphanum de 8 de long. La position de début sera déduite automatiquement en fonction des longueurs de C1PAYS et C1RAISON dans le fichier. Il suffit de recompiler le programme si C1PAYS ou C1RAISON venaient à changer de longueur. OVERLAY D DDSNAMVAR D NAMVAR D NAMVAR5 DS 20 10 5 OVERLAY(DSNAMVAR:10) OVERLAY(DSNAMVAR:10) La Data Structure est composée de : Une zone Alphanum. DSNAMVAR de 20 de long Une s/zone Alphanum. NAMVAR en position 10 de DSNAMVAR 10 de long Une s/zone Alphanum NAMVAR5 en position 10 de DSNAMVAR 5 de long Le mot clé OVERLAY permet des recouvrements de zones. OVERLAY(name[ :pos]) :pos est la position de début dans la zone (par défaut 1) Remarque : ici la data structure n’a pas de nom. Nous reviendrons aux data structures lorsque nous traiterons les tableaux. 14 15 CHAPITRE I ILE RPG I.2) Accès bases de données CHAIN C* C* Accès : CLIPAYS Pays C CLIPAYS001 KLIST C* Code Pays C KFLD C3CODPAYS ………… CL0N01Factor1+++++++Opcode&ExtFactor2+++++++Result++++++++Len++D+HiLoEq C* C MOVEL(p) C1PAYS C3CODPAYS C *NOKEY CLEAR *ALL CLIPAYSR C CLIPAYS001 CHAIN CLIPAYSR 96 -) La KLIST CLIPAYS001 est une définition de clé(s) du fichier CLIPAYS. Avec nos générateurs, le nom de KLIST est composé du nom du fichier suivi du nombre de clés jusqu’à 99 maxi. -) C’est le nom du format de fichier qui est utilisé pour les opérations bases de données, ici CLIPAYSR. -) MOVEL(p) permet d’affecter le contenu de la clé étrangère dans la clé pays afin d’y accéder. (p) met à blanc la zone résultat. Ici MOVEL(p) est strictement équivalent à EVAL, sauf pour le cas où C3CODPAYS serait alphanumérique et C1PAYS numérique. En effet, EVAL ne peut être une instruction valide que pour des données de même nature (tout alpahanum. ou tout num.) C *NOKEY CLEAR *ALL CLIPAYSR CLEAR est une instruction très puissante, connue depuis le RPGIII, qui initialise tous les champs du format CLIPAYSR à zéro et à blanc avant la lecture, sauf les clés *NOKEY. Ainsi, lors de la lecture en boucle et de l’affichage dans les lignes d’un sousfichier ou d’une édition, si l’accès échoue, le programme ne récupère pas une valeur déphasée de l’avant dernière lecture. CHAIN(n) C PROSPEC001 CHAIN(n) PROSPECTR 60 Si le fichier est déclaré en mise à jour en carte F, CHAIN(n) ne bloque pas l’enregistrement en lecture. Notons qu’un fichier peut être ouvert en partagé en dehors du programme en mise à jour avec une instruction CL : OVRDBF SHARE(*YES) suivie d’un OPEN. Dans ce cas, le programme ne tient aucun compte de la déclaration Input du fichier en carte F, puisque l’ouverture du fichier est partagée par plusieurs programmes ; dans ce cas une lecture bloquera l’enregistrement sauf si CHAIN(n). 15 16 CHAPITRE I ILE RPG I.2) Accès bases de données %EOF CL0N01Factor1+++++++Opcode&ExtFactor2+++++++Result++++++++Len++D+HiLoEq C PROSPEC001 CHAIN(n) PROSPECTR 60 C IF NOT %EOF(PROSPECTL5) …………… C ENDIF NOT %EOF(PROSPECTL5) indique SI NON fin de fichier PROSPECTL5. Il existe une autre syntaxe équivalente plus courte et plus classique : CL0N01Factor1+++++++Opcode&ExtFactor2+++++++Result++++++++Len++D+HiLoEq C PROSPEC001 CHAIN(n) PROSPECTR 60 C IF *IN60 = *OFF …………… C ENDIF Ou encore IF NOT(*IN60). Remarque: dans les transactionnels des générateurs avec sous-fichiers, l’indicateur *IN60 conditionne également le mot clé DSPF SFLEND qui affiche ou non le « + » ou « à suivre » en bas du sous-fichier. Cet indicateur 60 doit donc être coordonné avec l’indicateur de lecture de fin de fichier. CL0N01Factor1+++++++Opcode&ExtFactor2+++++++Result++++++++Len++D+HiLoEq C READ(n) PROSPECTR 60 C DOW *IN60 = *OFF …………… C READ(n) PROSPECTR 60 C ENDDO READ effectue une lecture suivante au fichier PROSPECTL5, format PROSPECTR dans l’ordre des clés. READ READE STELL CL0N01Factor1+++++++Opcode&ExtFactor2+++++++Result++++++++Len++D+HiLoEq C PROSPEC001 KLIST C* Code Pays C KFLD C1PAYS …………….. C EVAL C1PAYS = ‘FRA’ C PROSPEC001 SETLL PROSPECTR C PROSPEC001 READE(n) PROSPECTR 60 C DOW NOT %EOF(PROSPECTL5) …………… C PROSPEC001 READE(n) PROSPECTR 60 C ENDDO READE effectue la lecture suivante du groupe dont les clés sont définies dans la KLIST PROSPEC001 SETLL effectue un positionnement du curseur sur le premier élément du groupe ‘FRA’ d’enregistrements. IMPORTANT : notez la structure : 1ère lecture avant la répétitive DOW Lecture suivante avant le ENDDO Cette structure s’appelle « lecture en tête ». Elle est utilisée partout dans les programmes générés. La lecture avant le ENDDO permet de détecter la fin de fichier afin de sortir de la boucle. Si le fichier READ ou le groupe d’enregistrements du fichier READE est vide, la sortie de boucle est immédiate. 16 17 CHAPITRE I ILE RPG I.2) Accès bases de données CHAIN DOW …. READE ENDDO READP READPE C C PROSPEC001 C …………… C PROSPEC001 C EVAL CHAIN(n) DOW C1PAYS = ‘FRA’ PROSPECTR NOT %EOF(PROSPECTL5) READE(n) ENDDO PROSPECTR 60 60 L’instruction CHAIN sur clé partielle majeure PAYS est équivalente à un SETLL+READE de l’exemple plus haut. Car l’instruction CHAIN sur clé partielle effectue implicitement les opérations suivantes : -) SETLL positionnement sur le premier enregistrement du groupe -) READE lecture du premier enregistrement du groupe READP lecture précédente. L’indicateur indique alors le début de fichier (et non la fin de fichier). READPE lecture précédente du groupe (clés majeures définies dans la KLIST comme READE). L’indicateur indique le début du groupe. REMARQUE : READP est le pendant de READ avec lecture arrière READPE est le pendant de READE avec lecture arrière ……….. MOVE, EVAL etc… des champs de l’enregistrement à créer WRITE CL0N01Factor1+++++++Opcode&ExtFactor2+++++++Result++++++++Len++D+HiLo C WRITE PROSPECTR CL0N01Factor1+++++++Opcode&ExtFactor2+++++++Result++++++++Len++D+HiLo C PROSPEC001 CHAIN PROSPECTR 60 C IF NOT(*IN60) UPDATE ……….. MOVE, EVAL etc… des champs de l’enregistrement à modifier C C UPDATE ENDIF PROSPECTR NOTE: le CHAIN doit être sans (n) afin de locker l’enregistrement avant UPDATE L’enregistrement doit être trouvé pour que la mise à jour puisse s’effectuer C IF NOT(*IN60) IF %FOUND(PROSPECTL5) Est équivalent à C DELETE CL0N01Factor1+++++++Opcode&ExtFactor2+++++++Result++++++++Len++D+HiLo C PROSPEC001 CHAIN PROSPECTR 60 C IF %FOUND(PROSPECTL5) C DELETE PROSPECTR C ENDIF NOTE: le CHAIN doit être sans (n) afin de locker l’enregistrement avant DELETE L’enregistrement doit être trouvé pour que l’annulation puisse s’effectuer C IF NOT(*IN60) IF %FOUND(PROSPECTL5) Est équivalent à C 17 18 I.3) Instructions de base EVAL CHAPITRE I ILE RPG L’instruction EVAL est polymorphe en ILE RPG. Autrement dit, c’est le contexte qui indique l’action de cette instruction. En effet, si tous les données sont alphanumériques : une concaténation est effectuée ; si toutes les données sont numériques : un calcul est effectué. Il n’est donc pas possible de mixer des données numériques et alphanumériques avec EVAL (contrairement à MOVE ou MOVEL). EVAL calculs : Soit a programmer la formule suivante en ILE RPG et en RPGIII : TotalTTC = TotalHT + (TotalHT * Taux / 100) En ILE RPG nous aurons par exemple: EVAL(h) calculs CL0N01Factor1++Opcode&ExtExtended-factor2++++++++++++++++ C EVAL(H) TOTTTC = TOTHT + (TOTHT * TAUX / 100) Remarques : -) L’opération peut se continuer sur plusieurs lignes au besoin. -) EVAL(h) TOTTTC arrondi selon la règle du 5 Half. Nous constatons qu’il n’y a aucune différence de syntaxe entre l’opération formulée manuellement et celle codée en ILE RPG. D’où une facilité de lecture du code et d’apprentissage. -) Important : avec EVAL la donnée résultat est toujours remise à zéro avant l’opération effective. Voici maintenant la même opération en RPGIII. Notons que toutes les opérations MULT, DIV, ADD, SUB, Z-ADD existent toujours en ILE RPG et il convient donc de les connaître : CL0N01N02N03Factor1+++OpcdeFactor2+++Result C *LIKE DEFN TOTTTC ZTTC C TOTHT MULT TAUX ZTTC C ZTTC DIV 100 ZTTC C TOTHT ADD ZTTC TOTTTC Notons que le résultat final risque de ne pas être tout à fait le même en RPGIII à cause du problème des arrondis intermédiaires. 18 19 I.3) Instructions de base ADD CHAPITRE I ILE RPG Les instructions ADD, SUB, MULT, DIV et Z-ADD sont toujours très utilisées en ILE RPG dans la pratique. ADD permet d’effectuer un cumul et Z-ADD une mise à zéro préalable avant une addition. Voici quelques exemples avec l’équivalent EVAL : RPGIII ou ILE RPG CL0N01N02N03Factor1+++OpcdeFactor2+++Result C ADD 1 COMPTEUR OU : CL0N01Factor1++Opcode&ExtExtended-factor2++++++++++++++++ C EVAL COMPTEUR = COMPTEUR + 1 OU : CL0N01Factor1++Opcode&ExtExtended-factor2++++++++++++++++ C EVAL COMPTEUR += 1 Note : Dans ce cas, la valeur initiale de COMPTEUR est cumulée de +1. De la même manière : SUB CL0N01N02N03Factor1+++OpcdeFactor2+++Result C SUB 1 COMPTEUR OU : CL0N01Factor1++Opcode&ExtExtended-factor2++++++++++++++++ C EVAL COMPTEUR = COMPTEUR - 1 OU : CL0N01Factor1++Opcode&ExtExtended-factor2++++++++++++++++ C EVAL COMPTEUR -= 1 Multiplication : MULT CL0N01N02N03Factor1+++OpcdeFactor2+++Result C MULT 2 ZONE OU : CL0N01Factor1++Opcode&ExtExtended-factor2++++++++++++++++ C MULT ZONE = ZONE * 2 OU : CL0N01Factor1++Opcode&ExtExtended-factor2++++++++++++++++ C EVAL ZONE *= 2 Division : DIV CL0N01N02N03Factor1+++OpcdeFactor2+++Result C DIV 2 ZONE OU : CL0N01Factor1++Opcode&ExtExtended-factor2++++++++++++++++ C EVAL ZONE = ZONE / 2 OU : CL0N01Factor1++Opcode&ExtExtended-factor2++++++++++++++++ C EVAL ZONE /= 2 De la même manière il existe également **= 19 20 I.3) Instructions de base DIV MVR CHAPITRE I ILE RPG MVR permet de récupérer le reste d’une division en RPGIII ou ILE RPG. Ici, REMAINDER contiendra le reste de la division ou zéro si ZONE est divisible par 3. C C DIV MVR 3 ZONE REMAIDER Note : l’instruction MVR doit suivre immédiatement l’instruction DIV. Voici maintenant comment tester la numéricité d’une zone alphanumérique RPGIII ou ILE RPG : TESTN CL0N01Factor1+++++++Opcode&ExtFactor2+++++++Result++++++++Len++D+HiLoEq C TESTN ZONEAL 97 C N97 MOVE *ZEROS ZONEAL ZONEAL est un champ alphanumérique. Si ZONEAL contient que des caractères numériques de 0 à 9, l’indicateur 97 sera mis à *ON. Si ZONEAL ne contient pas que du numérique, l’instruction suivante MOVE *ZEROS remplit ZONEAL avec des zéros. Note : serait équivalent la syntaxe suivante : CL0N01Factor1+++++++Opcode&ExtFactor2+++++++Result++++++++Len++D+HiLoEq C TESTN ZONEAL 97 C IF NOT(*IN97) C EVAL ZONEAL = *ZEROS C ENDIF Remarque : *ZERO peut être employé également avec une variable numérique. Dans ce cas si ZONENUM est numérique : Z-ADD *ZERO CL0N01Factor1+++++++Opcode&ExtFactor2+++++++Result++++++++Len++D+HiLoEq C Z-ADD *ZEROS ZONENUM Equivalent à: C EVAL ZONENUM = *ZEROS Equivalent à : CL0N01Factor1+++++++Opcode&ExtFactor2+++++++Result++++++++Len++D+HiLoEq C CLEAR ZONENUM 20 21 CHAPITRE I ILE RPG I.3) Instructions de CLEAR est une instruction polymorphe qui met à zéro une donnée numérique et à blanc une donnée alphanumérique. CLEAR est également base capable de mettre à blanc et à zéro une structure de données. Voici quelques exemples : CLEAR DSTRUCDS D DSZONE1 D DSZONE2 D DSZONE3 DS 256 LIKE(C1PAYS) LIKE(C1RAISON) 8 CL0N01Factor1+++++++Opcode&ExtFactor2+++++++Result++++++++Len++D+HiLoEq C CLEAR STRUCDS Toutes les sous-zones de la data structure STRUCDS seront mises à blanc ou à zéro selon qu’elles sont alphanumériques ou numériques. C C *NOKEY CLIPAYS001 CLEAR CHAIN *ALL CLIPAYSR CLIPAYSR 96 Dans cet autre exemple, toutes les données du format de fichier CLIPAYSR, sauf les clés, seront remis à blanc ou à zéro avant la lecture avec les avantages suivant : -) on ne récupère pas une valeur d’une lecture précédente si la lecture échoue. -) en maintenance, un champ supplémentaire qui sera ajouté sera remis à blanc ou à zéro automatiquement après recompilation du programme. De la même manière, il est possible de mettre à blanc ou à zéro tous les postes d’un tableau comme nous verrons plus loin. 21 22 CHAPITRE I ILE RPG I.3) Instructions La déclaration d’un tableau diffère du RPGIII car les cartes E ont disparu. Ainsi, pour déclarer un tableau TZ10 avec 20 postes de 10 de long en RPGIII : de base DIM(nn) E....FromfileTofile++Name++N/rN/tbLen E TZ10 20 10 Equivalent en ILE RPG : DTZ10 S 10 DIM(20) La longueur décrite est celle d’un poste en carte D. DIM(20) indique qu’il y a 20 occurrences de ce poste. Donc la longueur effective totale de TZ10 est de 20 postes * 10 = 200 caractères. Voyons maintenant une déclaration de tableau en tant que poste d’une data structure : D D FLD1 D FLD2 DS 5 INZ('ABCDE') INZ 1 DIM(5) OVERLAY(FLD1) DIM OVERLAY Ici, la Data Structure est composée de : Un champ FLD1 alphan. De 5 de long initalisé INZ avec la constante ‘ABCDE’ Un tableau FLD2 dont un poste est de longueur 1 soit 5 de long au total. D’autre part, OVERLAY(FLD1) indique que le tableau FLD2 partage la même zone de mémoire, donc le contenu de chacun des postes de FLD2 sera : Le poste 1 contient ‘A’ Le poste 2 contient ‘B’ Le poste 3 contient ‘C’ Le poste 4 contient ‘D’ Le poste 5 contient ‘E’ Nous avons un équivalent : DFLD1 S 5 INZ('ABCDE') DFLD2 S 1 DIM(5) CL0N01Factor1+++++++Opcode&ExtFactor2+++++++Result++++++++Len++D+HiLoEq C MOVEA FLD1 FLD2(1) Dans cet exemple, les deux zones sont déclarées séparément Single en carte D. L’instruction MOVEA peuple le tableau FLD2 à partir du poste 1. Le contenu des postes sera équivalent à l’exemple précédent. Remarque : noter la syntaxe pour un poste d’un tableau TABEAU(p) 22 23 CHAPITRE I ILE RPG I.3) Instructions Soit lire le tableau FLD2 de 5 postes de l’exemple précédent dans une boucle : de base DO …….. T(nn) …….. ENDDO Di DZONE S S 5 1 0 CL0N01Factor1+++++++Opcode&ExtFactor2+++++++Result++++++++Len++D+HiLoEq C DO 5 I C………. C EVAL ZONE = FLD2(i) C………. C ENDDO La valeur de I est incrémenté 5 fois : boucle DO….ENDDO. La variable ZONE prendra la valeur ‘A’ pour i=1……’E’ pour i=5 Pour rechercher l’indice correspondant au contenu d’un poste d’un tableau alphanumérique, en RPGIII nous avions l’instruction LOKUP et en ILE RPG LOOKUP. LOOKUP CL0N01Factor1+++++++Opcode&ExtFactor2+++++++Result++++++++Len++D+HiLoEq C EVAL I = 1 C ‘C’ LOOKUP FLD2(i) 20 I prendra la valeur 3 car le poste 3 contient ‘C’. D’autre part l’indicateur 20 sera égal à *ON trouvé. SORTA CL0N01Factor1+++++++Opcode&ExtFactor2+++++++Result++++++++Len++D+HiLoEq C MOVEA ‘CABFDE’ FLD2(1) C SORTA FLD2 SORTA Effectue le tri du tableau : FLD2 contiendra ‘ABCDEF’. XFOOT DTOTAL S 6 Dtn S 5 C EVAL tn(1) C EVAL tn(2) C EVAL tn(3) C EVAL tn(4) C XFOOT tn * Après : TOTAL contiendra 17 C EVAL *INLR 0 0 = = = = DIM(4) 5 2 6 4 TOTAL = *ON XFOOT effectue le total des postes d’un tableau numérique. 23 24 CHAPITRE I ILE RPG I.3) Instructions de base ADDDUR SUBDUR *days *months *years HDATFMT(*ISO) DNUM_8 DNUM_6 DALP_8 DZ6V0 DZ8V0 DDATISO DDATDMY * 1°) convertir C *YMD * note 4 C * note 5 C *YMD0 * note 3 C *YMD * note 2 S 8 0 INZ(19960312) S 6 0 INZ(960312) S 8 INZ('19960312') S 6 0 S 8 0 S D S D DATFMT(*DMY) données num. ou alphanum. Vers données Date. MOVE NUM_6 DATISO '1996-03-12' MOVE NUM_8 DATISO '1996-03-12' MOVE ALP_8 DATISO '1996-03-12' MOVE NUM_8 DATDMY '12/03/96' * 2°) Ajouter 1 an 2 mois et 10 jour à DATISO puis enlever 6 mois ADDDUR 10:*days DATISO ADDDUR 2:*months DATISO ADDDUR 1:*years DATISO * '1997-05-22' C SUBDUR 6:*months DATISO * '1996-11-22' * 3°) convertir données Date Vers données numériques alphanum. C MOVE DATISO Z8V0 * 19961122 C MOVE DATISO ALP_10 * ‘1996-11-22’ C *YMD MOVE DATISO Z6V0 * note 5 '961122' C *YMD0 MOVE DATISO ALP_8 * note 5 note 2 '19961122' C EVAL *INLR = *ON C C C L’exemple ci-dessus simule des dates numériques ou alphanumériques qui seraient issues d’un fichier afin de les convertir et/ou d’y ajouter une période. Note 1 : la donnée DATISO est de format Date. Le format date doit normalement être indiqué, s’il ne l’est pas, c’est la définition du format date en carte H qui s’applique : H DATFMT(*ISO) Note 2 : la donnée DATDMY est de format date *DMY. Soit ‘12/03/96’. Note 3 : *YMD0 la donnée ALP_8 étant alphanumérique de 8, 0 indique qu’il n’y a pas de séparateur. Note 4 : *YMD s’applique à une donnée numérique de 6 ou de 8 de long. Si la donnée est numérique de 6, le ILE RPG déduit le siècle. Note 5 : Si la donnée numérique est différente de 8 ou alphanumérique de 10, il faut préciser *YMD ou *YMD0 pour le format. Nous voyons que la syntaxe de conversion est très simple. Il est très simple également en ILE RPG d’ajouter ADDDUR ou retrancher SUBDUR une durée à une donnée de type Date. 24 25 CHAPITRE I ILE RPG I.3) Instructions de base Date et heure du jour, horodatage *hours *minutes *secondes CLEAR *ms HDATFMT(*ISO) DDATISO S D DTIMSTART S T DHORODATAGE S Z DZ26 S 26 * date du jour heure de l'instant C MOVE *date DATISO * '2006-03-05' C TIME TIMSTART * '16.08.10' C TIME HORODATAGE * ‘2006-03-05-16.08.10.309000’ * Ajouter 2 heures à l'heure de l'instant C ADDDUR 2:*hours TIMSTART * Ajouter 2 minutes à l'heure de l'instant C ADDDUR 2:*minutes TIMSTART * Ajouter 2 secondes à l'heure de l'instant C ADDDUR 2:*seconds TIMSTART * '18.10.12' * note 1 initialiser et peupler HORODATAGE C CLEAR HORODATAGE * ‘0001-01-01-00.00.00.000000’ C MOVE DATISO HORODATAGE C MOVE TIMSTART HORODATAGE * '2006-03-05-18.10.12.000000' * note 2 ajouter 1234 millisecondes et 12 jours à HORODATAGE C ADDDUR 1234:*ms HORODATAGE C ADDDUR 12:*days HORODATAGE * sans séparateur *ISO0 dans un champ alphanum. de 26c C *ISO0 MOVE HORODATAGE Z26 * '20060317181012001234' C EVAL *INLR = *ON Note 1 : MOVE permet de peupler une zone de type z horodatage car nous avons respectivement une zone de type D et une zone de type T en facteur 2. Note 2 : Il est possible d’ajouter ou retrancher des jours, mois, ans, heures, minutes, secondes, ms, à la zone de type Z horodatage. ============================================== Comment calculer le nombre de jours entre deux dates par exemple alphanumériques provenant d’un fichier ? Ici date jj/mm/aa - mmjjaaaa en nombre de jours SUBDUR nombre de jours entre deux dates HDATFMT(*ISO) DZ8A DZ8B DDATISO1 DDATISO2 DZ8V0 C *DMY/ C *USA0 C DATISO1 C** 2006-12-10 C S S S S S MOVE MOVE SUBDUR EVAL 8 INZ('10/12/06') 8 INZ('02062005') D D 8 0 Z8A DATISO1 Z8B DATISO2 DATISO2 Z8V0:*D 2005-02-06 = 672 jours *INLR = *ON 25 26 CHAPITRE I ILE RPG I.3) Instructions de base Contrôle validité date TEST(DE) HDATFMT(*ISO) DDATISO S D DZ6V0 S 6 0 INZ(005544) * * tester la validité d'une date numérique provenant d'un fichier C *DMY TEST(DE) Z6V0 * C IF %ERROR C CLEAR DATISO C ELSE C *DMY MOVE Z6V0 DATISO C ENDIF * DATISO = '0001-01-01' * date valide C EVAL Z6V0 = 051098 C *DMY TEST(DE) Z6V0 * C IF %ERROR C CLEAR DATISO C ELSE C *DMY MOVE Z6V0 DATISO C ENDIF * DATISO = '1998-10-05' C EVAL *INLR = *ON Remarque : *DMY implique que la date est sur 6 de long.. TEST(DE) permet de tester la validité d’une Date. Si la date est en erreur, le test qui suit IF %ERROR ou un indicateur *ON à droite sous = permet de détecter l’erreur. Il y a l’équivalent TEST(TE) pour tester une donnée de type T Time. *loval *hival C CLEAR * C MOVE *LOVAL MOVE *HIVAL * C * DATISO ‘0001-01-01’ DATISO ‘0001-01-01’ DATISO ‘9999-12-31’ *LOVAL ou CLEAR et *HIVAL permettent d’initialiser une date *iso à la valeur la + basse puis à la valeur la + haute. ============================================= Quelques formats date courants : Autres formats date DDATJUL DDATUSA DDATEUR DZ6V0 C *DMY * C *DMY * C *DMY * C S S S S D D D DATFMT(*JUL) DATFMT(*USA) DATFMT(*EUR) 6 0 INZ(200306) MOVE Z6V0 DATJUL an/nbr jours '06/079' MOVE Z6V0 DATUSA mm/jj/aaaa '03/20/2006' MOVE Z6V0 DATEUR jj.mm.aaaa '20.03.2006' EVAL *INLR = *ON 26 27 CHAPITRE I ILE RPG I.3) Instructions de Voici maintenant un exemple de tableau à n dimensions dont les postes sont chargés à la compilation. base POSTAL est un tableau dont le poste est de 26 de long ; 5 postes. Chaque poste est subdivisé en CODPOST 6 de long et VILLE 20 de long REGION 2 de long également 2 premiers caractères de CODPOST. L’exemple consiste a rechercher la ville du code postal CODPOST dont le Tables contenu est égal à ‘59000’ Le programme a été compilé et testé avec le chargées à la debogue pas à pas d’IBM comme nous verrons dans le chapitre suivant : compilation. CTDATA n dimensions PERRCD(n) HDEBUG D DS DPOSTAL 26 DIM(5) PERRCD(1) CTDATA D REGION 2 OVERLAY(POSTAL:1) D CODPOST 6 OVERLAY(POSTAL:1) D VILLE 20 OVERLAY(POSTAL:7) Di S 5 0 DZONE S 20 * ------------------------------------------------------------------ * C EVAL i = 1 C '59000 ' LOOKUP CODPOST(i) 20 C* C IF *IN20 C EVAL ZONE = VILLE(i) C ENDIF C* C SORTA VILLE C* C SETON LR **CTDATA POSTAL 75000 PARIS 13000 LA ROCHELLE 51600 SUIPPES 59000 LILLE 59222 BOUSIES Remarque : la longueur est définie pour un seul poste. Ainsi, un poste de POSTAL est de longueur 26. Les deux postes CODPOST et VILLE recouvrent OVERLAY le poste POSTAL. Dans le programme, nous voyons que CODPOST et VILLE sont des sous-tableaux. Le mot clé CTDATA permet de charger le contenu d’un tableau à la compilation, ce contenu étant précisé à la fin du programme ILE RPG à partir de la position 1. **CTDATA POSTAL est obligatoire et indique que le contenu des lignes du tableau POSTAL commence après. Le mot clé PERRCD(1) signifie qu’il n’y a qu’un poste POSTAL pour chaque ligne qui suit **CTDATA POSTAL. SORTA VILLE : bien entendu, CODPOST et REGION suivront en parallèle le tri de VILLE, car le tri s’effectue sur POSTAL, dans l’ordre de la sous-zone VILLE. 27 28 CHAPITRE I ILE RPG MOVE : Peuple la partie droite d’un champ résultat. I.3) Instructions MOVEL : Peuple la partie gauche d’un champ résultat. Particularités : de base MOVE et MOVEL ne remettent pas à blanc ou à zéro le champ résultat avant de le peupler. Les octets non peuplés contiendront donc les anciennes valeurs. MOVE(p) et MOVEL(p) remettent à blanc ou à zéro le champ résultat avant de MOVE le peupler. MOVEL Polymorphisme de MOVE et MOVEL: MOVE et MOVEL peuvent peupler des champs de nature différente. Par exemple de l’alphanumérique dans du numérique ou du numérique dans de l’alphanumérique. Ces instructions sont donc très puissantes. Notons que le numérique peut être étendu ou packé. Mais si un champ alphanumérique doit peupler un champ numérique, il doit contenir uniquement des 0..9. Un test préalable de numéricité TESTN est donc indispensable dans ce cas. Voici quelques exemples : TESTN *ALL’a’ DZ10ALPHA S 10 INZ('ABCDEFGHIJ') DZ5NUM S 5 0 INZ(22222) DW5ALPHA S 5 INZ('12345') DZ8NUM S 8 0 INZ(34343434) DZ15NUM S 15 0 INZ(0123456789012345) * C MOVE W5ALPHA Z10ALPHA * Après Z10ALPHA = 'ABCDE12345' C MOVEL W5ALPHA Z10ALPHA * Après Z10ALPHA = '1234512345' C MOVEL Z5NUM Z10ALPHA * Après Z10ALPHA = '2222212345' CL0N01Factor1+++++++Opcode&ExtFactor2+++++++Result++++++++Len++D+HiLoEq C TESTN Z10ALPHA 20 C IF *IN20 C MOVE Z10ALPHA Z15NUM C ELSE C CLEAR Z15NUM C ENDIF * Après Z15NUM 0123452222212345 C MOVE *ALL'A' Z10ALPHA * Après Z10ALPHA = 'AAAAAAAAAA' C MOVEL *ON *INLR Remarques : TESTN : si Z10ALPHA est numérique, *IN20 = *ON *ALL’A’ : peuple Z10ALPHA avec des A. 28 29 CHAPITRE I ILE RPG EVAL permet de concaténer des champs alphanumériques. Cependant, cette I.3) Instructions de concaténation est brute comme dans l’exemple suivant : base EVAL pour alphanum. DPRENOM1 S DPRENOM2 S DNOM S DNOMPRENOM S * C EVAL C * Après : NOMPRENOM = 'Jean C EVAL 10 10 10 30 INZ('Jean ') INZ('Etienne ') INZ('LAFLECHE ') INZ('AAAAAAAAAAAAAAAAAAA') NOMPRENOM = PRENOM1 + PRENOM2 + NOM Etienne LAFLECHE ' *INLR = *ON Note : avec EVAL, tous les champs doivent être soit alphanumériques, soit numériques : nous aurons respectivement une concaténation dans un cas et un calcul dans l’autre. Seul l’opérateur + est admis pour une concaténation. Ici, l’opération de concaténation est exprimée sur plusieurs lignes. Attention : + en bout de ligne est un opérateur de concaténation et n’indique en rien une quelconque continuation à la ligne suivante ! CAT associé à EVAL permet des concaténations plus élaborées, comme dans l’exemple suivant : CAT Facteur2:1 DPRENOM1 S 10 INZ('Jean ') DPRENOM2 S 10 INZ('Etienne ') DNOM S 10 INZ('LAFLECHE ') DNOMPRENOM S 30 INZ('AAAAAAAAAAAAAAAAAAA') * C EVAL NOMPRENOM = PRENOM1 * Après NOMPRENOM = 'Jean ' C NOMPRENOM CAT PRENOM2:1 NOMPRENOM * Après NOMPRENOM = 'Jean Etienne ' C NOMPRENOM CAT NOM:1 NOMPRENOM * Après NOMPRENOM = 'Jean Etienne LAFECHE ' C SETON LR Bien entendu, CAT ne remet pas à blanc avant afin de permettre des concaténations en série. Facteur2 :1 indique qu’il y aura un blanc entre le facteur1 et le facteur2. Ainsi, Facteur2 :0 exécute une concaténation sans blanc entre le facteur1 et facteur2. Le 1er EVAL met à blanc avant et peuple en justifiant à gauche. 29 30 CHAPITRE I ILE RPG I.3) Instructions de base %SUBST %LEN %TRIMR DLGR S 5 0 DPRENOM1 S 10 DPRENOM2 S 10 DNOM S 10 DNOMPRENOM S 30 INZ('Jean Etienne LAFLECHE * C MOVEL(p) NOMPRENOM PRENOM1 * Après : PRENOM1 = 'Jean ' C EVAL PRENOM2 = %SUBST(NOMPRENOM:11:10) * Après : PRENOM2 = 'Etienne ' C EVAL NOM = %SUBST(NOMPRENOM:21:10) * Après : NOM = 'LAFLECHE ' * C EVAL LGR = %LEN(PRENOM1) * Après : LGR = 10 longueur totale du champ PRENOM1 C EVAL LGR = %LEN(%TRIMR(PRENOM1)) * Après : LGR = 4 longueur du contenu du champ PRENOM1 'Jean' C EVAL *INLR = *ON Remarque : %LEN(%TRIMR(champ)) retourne la longueur du contenu du champ sans les blancs à droite. %LEN(champ) retourne la longueur totale du champ indépendamment de son contenu (les blancs à droite sont comptés). %SUBST(champ :position de début :longueur) permet une extraction à l’intérieur d’une chaîne de caractères à condition de connaître la position de début et la longueur. Dans l’exemple suivant le séparateur de champ ; est détecté avec un SCAN : SCAN %SUBSTR DD S 5 0 DF S 5 0 DLGR S 5 0 DNOMPRENOM S 30 INZ('Jean;Etienne;LAFLECHE') DPRENOM1 S 10 DPRENOM2 S 10 * C ';' SCAN NOMPRENOM D * Après : D = 5 *IN20 = *ON C IF *IN20 C EVAL PRENOM1 = %SUBST(NOMPRENOM:1:D-1) * Après : PRENOM1 = 'Jean ' C ENDIF * C EVAL D = D + 1 C ';' SCAN NOMPRENOM:D F C EVAL LGR = F - D * * Après : F = 13 D = 6 LGR = 7 C IF *IN20 AND D < F C EVAL PRENOM2 = %SUBST(NOMPRENOM:D:LGR) * Après : PRENOM2 = 'Etienne ' C ELSE C EVAL PRENOM2 = *BLANKS C ENDIF * C EVAL *INLR = *ON Remarque : facteur2 :D indique la position de début de la recherche dans la chaîne de caractères. 1 par défaut. 30 20 20 31 CHAPITRE I ILE RPG I.3) Instructions de base API QCLSCAN DQCLSCAN PR EXTPGM('QCLSCAN') D CharString 1024 D LenghtOfChar 3 0 D StartingPosit 3 0 const D CharPattern 1024 D LengthOfChar 3 0 D TranslateChar 1 const D TrimTrailingBl 1 const D WidcardChar 1 const D CharStringRes 3 0 DWString S 1024 DWStrLen S 3 0 DWPattern S 1024 DWPatLen S 3 0 DWResult S 3 0 DWSelData S 1 …………………………………………………………………… C BEGSR ……………………………………………………….. C* SCAN ; Raison Sociale. Fichier: EXCLIENT Client Exemples Fast C IF SCC1RAIS51 <> *BLANK C EVAL WString = C1RAISON C EVAL WStrLen = %Len(%Trim(C1RAISON)) C EVAL WPattern = SCC1RAIS51 C EVAL WPatlen = %Len(%Trim(SCC1RAIS51)) C CALLP QCLSCAN(WString:WStrLen:1: C WPattern:WPatLen:'1':'1': C '*':WResult) C* C IF WResult <= *zero C EVAL WSelData = *OFF C LEAVESR C ENDIF C* C ENDIF …………………………………………………………………………. C ENDSR Dans ce dernier exemple sur les instructions ILE RPG, nous utilisons l’API IBM QCLSCAN. Nous utilisons QCLSCAN plutôt que le SCAN ILE RPG à cause de la traduction des majuscules en minuscules pour la recherche et du caractère de remplacement ‘*’ dans les programmes de critères de sélection et surtout de l’optimisation. Nous avons là un exemple de calcul de la longueur du contenu des deux variables afin d’optimiser le SCAN, sans quoi il effectuerait la recherche sur toute la longueur du champ cible, soit 1024 caractères. Notons que %TRIM est équivalent à %TRIMR (sans les blancs à droite). Notons également l’utilisation de LEAVESR afin de sortir immédiatement du sous-programme, dans un but d’optimisation, si le SCAN n’a pas été trouvé. CONCLUSION : ILE RPG est un langage de gestion très puissant. Pour la gestion classique, il convient de se limiter aux instructions de base afin de garder un contrôle intellectuel sur les applications sur le long terme. Mais il faut savoir qu’en cas de nécessité, des instructions ILE RPG pointues sont à disposition du développeur. 31 32 Partie II Personnaliser les programmes 32 33 CHAPITRE II Personnaliser les programmes II.1) Debogue IBM ILE RPG Conseil : pour ajouter des instructions dans un programme, il est souvent nécessaire d’avoir le contenu de toutes les données de tous les fichiers. Or, le contenu des données qui ne sont pas utilisées par le programme ILE RPG ne peut pas être affiché. En effet, seules les données utiles sont effectives dans un but d’optimisation de la place mémoire d’un programme à l’exécution. C’est pourquoi nous conseillons d’ajouter en carte H DEBUG le temps du debogue et de l’enlever ensuite pour des raisons de place mémoire : HDEBUG =================================================== Préalable : pour qu’un programme ILE RPG puisse être debogué (un programme compilé avec le générateur est en mode debogue par défaut) il faut : Avec l’option 14 de PDM + F4, devant un membre source RPGLE, afficher les paramètres et modifier DBGVIEW(*ALL) : STRDBG CRTBNDRPG avec DBGVIEW(*ALL) ==================================================== Pour effectuer un debogue rapide d’un programme, procéder comme suit : 1°) lancer la commande STRDBG UPDPROD(*yes) Remarques : Si votre bibliothèque est de type TEST, UPDRPOD n’a pas d’utilité. Si votre bibliothèque est de type PROD : si STRDBG avec UPDPROD(*no) les données du programme ne seront pas mises à jour jusqu’au lancement de la commande ENDDBG qui termine le mode debogue. =================================================== 2°) lancer la commande DSPMODSRC Ouvrir une 3°) commande F14 vue source 4°) Saisir 1 puis le nom du programme : debogue Opt 1 Pgm/module abcsl2 Biblio *LIBL Type *PGM ENTREE 5°) Saisir 5 devant le *MODULE : Opt 5 Pgm/module abcsl2 ABCSL2 ABCSL2 Biblio *LIBL TSTLIBOBJ Type *PGM *PGM *MODULE Sélectionné 33 34 CHAPITRE II Personnaliser les programmes II.1) Debogue IBM ILE RPG Programme: 1 7 8 9 10 14 15 ABCSL2 Biblio: HDEBUG F* Ecran dspf : FABCSL2W CF E F F F* Prospects / Pays FPROSPECTL1IF E TSTLIBOBJ Module: ABCSL2 WORKSTN SFILE(WSFL:RRN) INFDS(DS_Display) K DISK Le source du programme s’affiche: Conseil : afficher toujours systématiquement la vue objet compilé : Vue objet 6°) commande F15 puis saisir 1 devant Vue Listage ILE RPG: Opt 1 Vue Vue listage ILE RPG Vue source ILE RPG Vue copie ILE RPG ===================================================== Ajouter/enlever les points d’arrêt : Ajout point Commande F06 point d’arrêt devant une ligne carte C non en commentaire. d’arrêt Pour rechercher une ligne de code précise : Lancer sur la ligne de commandes de debogage : TOP pour se positionner au début du programme. Rechercher puis comme avec SEU : F NomRecherche puis F16 pour rechercher éventuellement l’occurrence suivante comme avec SEU. Note : F09 commande précédente. ====================================================== Pour deboguer : Appeler le programme normalement. Il doit s’arrêter au point d’arrêt spécifié. S’il ne s’arrête pas, cela veut dire que le programme ne passe pas par les instructions du point de debogue. Voir ou forcer un contenu de variable ENDDBG Pour voir le contenu d’une variable : Lancer la commande EVAL nomvariable OU F11 le curseur étant positionné sur la variable. Pour visualiser le contenu en hexa. : EVAL NomVariable :x F10 pour aller à la ligne suivante F12 au point d’arrêt éventuel suivant. Pour forcer le contenu d’une variable : Lancer la commande : EVAL NomVariable = ‘NouvelleValeur’ ====================================================== ENDDBG : est le pendant de STRDBG et termine le mode debogue pour la session. 34 35 CHAPITRE II Personnaliser les programmes II.2 ) Ajout Comment ajouter un contrôle personnalisé dans une fiche ou d’un formulaire modèle de type FCH ? contrôle Pour ajouter un contrôle vous devez savoir : 1°) Le point du programme où ajouter le contrôle. 2°) Ajouter un message personnalisé dans un fichier messages. 3°) Ajouter le contrôle en ILE RPG 4°) Compiler + Tester le programme. Nous allons voir en détail ces points : 1°) Le sous-programme des contrôles. /SEU/ « Sous-prog. Du modèle » Rappel : pour visualiser les sous-programmes d’un modèle : R.A.D. Critère/S SEU_hlp Manage _________________________ ________________________ FastRPG Janvier 2006 Modifier Sources Environnement par défaut Compiler FCH En_cours: AV001FCH A ________________________ PDM d'IBM | F11=Date/Nom F10-v Sous-Prog. du modèle -----------------------| 2/03/06 | EDTCLPY Exemples pgms générés | 1/03/06 | ABCSL2 | 1/03/06 | ABDSL2 ABDSL2 | SL2 > 1/03/06 | AV001FCH AV001FCH | FCH Système __________ . *PGM dé re: EXCLI _________ ress.: 1 --------dition iste clas Liste clas Fiche ___________________________________________________________________ | | Nom | Fonction | Routine ------------------------------------------------------------------| AFFICHAGE DES ECRANS | SRDSP_2 | Affichage écrans en Création ou en Modification | SRDSP_2 | Affichage des écrans Visualisation OU Annulation | SRDSP_5 | CONTROLES ; APPLIQUER REGLES GESTION | SRCTL_2 | Structure, contrôle des pages | SRCTL_2 | Contrôle de la page 1 | SRWFCH1 | (1..9 pages maxi) | SRWFCH1 Le contrôle de la page 1 est SRWFCH1 … SRWFCH9. Il peut y avoir 9 pages maxi. Donc, allons dans le source avec SEU et recherchons le sous-programme SRWFCH1 : Nous voyons qu’à l’intérieur du « tiroir » SRWFCH1 il y a n compartiments, un par donnée à contrôler, avec un tag + indicateur + Page. C* C* ind. erreur = 11 C1KCLI Code Client C End_IN11P1 tag C* C* ind. erreur = 12 C1RAISON Raison Sociale C End_IN12P1 tag C* C* ind. erreur = 13 C1ADR1 Adresse lgn 1 C End_IN13P1 tag 35 36 CHAPITRE II Personnaliser les programmes II.2 ) Ajout Remarque : d’un Le tag est facultatif et est utilisé uniquement par le générateur pour contrôle regrouper les contrôles d’un même champ de saisie ensemble. Si le tag n’est pas présent, le générateur insère le contrôle avant le ENDSR. Les indicateurs d’erreur, pour chacune des pages, vont de 11 à 49. Chaque indicateur gère uniquement DSPATR(RI PC) au niveau du champ, soit le positionnement curseur et la reverse video. La gestion des messages est totalement indépendante. Il peut y avoir un nombre infini de messages d’erreur par champ contrôlé. Le texte du message d’erreur peut être géré en dehors du programme. Le tag : End_IN13P1 correspond par exemple à l’indicateur 13 de la page 1. =================================================== 2°) Ajouter un message personnalisé dans un fichier messages. Vous devez créer en premier le fichier messages pour votre société et en aucun cas prendre celui du générateur. Vous allez créer un fichier messages objet i5/OS de type *msgf avec la commande IBM si votre société s’appelle ABC et MYLIBOBJ ma bibliothèque objet courante : CRTMSGF MYLIBOBJ/ABCMSGF Ensuite il faut ajouter un message dans le fichier des messages avec l’une des deux commandes IBM ADDMSGD ou WRKMSGD : WRKMSGD MSGF(ABCMSGF) puis F06 ajouter un message Ajouter description de message (ADDMSGD) Indiquez vos choix, puis appuyez sur ENTREE. Identificateur de message . Fichier de messages . . . . Bibliothèque . . . . . . . Texte message de 1er niveau ville doivent être renseignés . . . . . MSGID . MSGF . . MSG ABC0001 > ABCMSGF > TSTLIBOBJ Le code postal et la Texte message de 2e niveau . . . SECLVL Si le code postal ou la ville sont renseignés, alors les deux doivent être renseignés. Sinon les deux doivent être laissés à blanc. Saisir le message de 1er niveau et le message de second niveau éventuellement. F05=Rafraichir Important : l’identifiant du message, ici ABC0001 doit commencer par 3 lettres puis 4 chiffres hexa. Soit 0..F 36 37 CHAPITRE II Personnaliser les programmes II.2 ) Ajout 3°) Ajouter le contrôle en ILE RPG d’un contrôle Nous allons maintenant ajouter le contrôle suivant : Si (le code postal OU la ville sont <> de blanc) ET (le code postal = blanc OU la ville = blanc) | erreur. Fin si Autrement dit : les deux doivent être renseignés ou les deux doivent être à blanc. Nous allons donc mettre en reverse video le code postal et la ville en cas d’erreur et envoyer à la file d’attente des messages du programme notre message identifiant : ABC0001 Emplacement : C* C* ind. erreur = 16 C1CODPOS Code Postal C IF (C1CODPOS <> *BLANK OR C C1VILLE <> *BLANK) C AND C (C1CODPOS = *BLANK OR C C1VILLE = *BLANK) C EVAL *IN16 = *ON C EVAL *IN17 = *ON C EVAL WMsgf = 'ABCMSGF' C EVAL WMsgId = 'ABC0001' C CALL 'WSNDMSG' WSndMsg C ENDIF C End_IN16P1 tag C* C* ind. erreur = 17 C1VILLE Ville C End_IN17P1 tag Le message d’erreur peut être inséré soit avant End_IN16P1, soit avant End_IN17P1 soit bien entendu avant le ENDSR. *IN16 et *IN17 vont mettre en reverse video les deux champs en erreur. Voir dans les DSPF l’ attribut DSPATR(RI). Remarque 1 : le programme WSNDMSG (dont vous avez le source. Voir brochure 1), envoie le message à la file d’attente du programme. Conseil : ne jamais utiliser le fichier des messages du générateur. Prendre le fichier des messages pour votre société uniquement. Remarque 2 : si nous ajoutons maintenant un contrôle par le générateur sur le champ C1CODPOS, il insèrera le contrôle avant le tag End_IN16P1. Bien entendu, sans toucher au contrôle personnalisé. 37 38 CHAPITRE II Personnaliser les programmes II.2 ) Ajout 4°) Compiler et tester d’un Code Postal. contrôle Ville. . . . . . . . .: . . . . .: Code Pays. . . . . . .: 75800 FRA France F9=Valider F12=Prédt. Le code postal et la ville doivent être renseignés Nous avons bien le code postal et la ville en reverse video. Si l’utilisateur place son curseur sur la ligne du message d’erreur et F01 ou AIDE, nous aurons le message de deuxième niveau mais aussi l’identifiant du message, ce qui est très utile en maintenance du programme. En effet, il suffit ensuite d’effectuer des recherches sur l’identifiant du message d’erreur dans le membre source, par exemple rechercher ‘ABC0001’ avec SEU. ID message . . . . . . : Type de message . . . : Date d'envoi . . . . . : ABC0001 Information 06/03/06 Gravité . . . . . . . : Heure d'envoi . . . . : 00 17 Message . . . . : Le code postal et la ville doivent être renseignés Si le code postal ou la ville sont renseignés, alors les deux sont obligatoires. Puis F09=Détails du message Programme de destination . . . : Bibliothèque . . . . . . . . : Module de destination . . . : Procédure de destination . . : Spécification destination . : AV001FCH TSTLIBOBJ AV001FCH AV001FCH 754 En plus de l’identifiant du message, nous obtenons avec F09 de suite le nom du programme lui même. Notez que AV001FCH est le programme de destination du message, le programme d’origine étant WSNDMSG. C’est une communication i5/OS dite de programme à programme. Nous avons également la ligne 754 qui correspond à la ligne de debogue avec F15 vue de l’objet (voir chapitre précédent). 750 751 752 753 754 C C C C C EVAL EVAL EVAL EVAL CALL *IN16 = *ON *IN17 = *ON WMsgf = 'ABCMSGF' WMsgId = 'ABC0001' 'WSNDMSG' WSndMsg 38 39 CHAPITRE II Personnaliser les programmes Le préaffichage d’une fiche permet de préafficher en création des informations II.3 ) Préaffichage dans des champs d’Entrée/Sortie. Le préaffichage en création répond en création généralement à une demande pressante des utilisateurs comme : - « 9 fois sur 10 je suis obligé de saisir la date du jour dans la date d’une fiche commande en création… » - « 8 fois sur 10 en création le code pays est le même » etc… Nos générateurs savent traiter ces cas les plus courant, cependant il existe toujours des spécificités en fonction de l’activité. Il faut donc savoir où insérer le préaffichage en création dans une fiche, c’est à dire connaître le bon sousprogramme : Sélectionner un programme de type FCH fiche à partir du menu principal : Sousprogramme d’un modèle R.A.D. Critère/S SEU_hlp Manage Syst _________________________ ________________________ ____ FastRPG Janvier 2006 Modifier Sources Environnement par défaut Compiler . * FCH En_cours: AV001FCH A re: ________________________ PDM d'IBM ___ | F11=Date/Nom F10-v Sous-Prog. du modèle res -------------------------| 6/03/06 | AVSL201 Exemples pgms générés ist | 2/03/06 | EDTCLPY dit | 1/03/06 | ABCSL2 ABCSL2 | SL2 List ____________________________________________________________________ | | Nom | | Fonction | Routine | -------------------------------------------------------------------| => STRUTURE GENERALE DE LA FICHE | *MAIN | | | *MAIN | | INITIALISATION | SRPLIST | | PLIST utilisés dans le module | SRPLIST | | KLIST utilisés dans le module | SRKLIST | | Initialisation en début de programme | SRINIT | | S/STRUCTURE DE NIVEAU 2 | SRWRK_2 | | S/Structure Création OU Modification fiche | SRWRK_2 | | S/Structure Annulation fiche | SRWRK_4 | | S/Structure Visualisation fiche | SRWRK_5 | | PREPARATION ECRANS AVANT AFFICHAGE | SRPRP_1 | | Préparation écran en création | SRPRP_1 | Le sous-programme s’appelle SRPRP_1. Il suffit d’insérer le préaffichage juste avant le ENDSR de ce sous-programme. Voyons un exemple : 39 40 CHAPITRE II Personnaliser les programmes Soit par exemple, préafficher ‘75000’ dans le code postal à chaque fois que le II.3 ) Préaffichage code pays est ‘FRA’ France. Nous supposerons que le code pays est passé en paramètre en création (clé majeure). Nous aurons les instructions suivantes en création avant le ENDSR du sous-programme SRPRP_1 : d’une fiche C SRPRP_1 BEGSR C ………………………………………………………………………………. C IF C1PAYS = 'FRA' C EVAL C1CODPOS = '75000' C ENDIF C* C ENDSR Ce qui nous donnera en Création Fiche après F6 à partir du sous-fichier : AVFCH01 Client par Pays Code Pays : FRA France Clé Client . . Raison Sociale Adresse lgn 1. Adresse lgn 2. Adresse lgn 3. Code Postal. . Ville. . . . . . . . . . . . . . . . . . . . . . . . . . .: .: .: .: .: .: .: Créer 000000 75000 ================================================ Le pré-affichage en non(création) c’est à dire en modification par exemple Préaffichage obéît au même principe mais avec le sous-programme SRPRP_2. Cependant, en attention : non(création) Le pré-affichage en non(création) est utilisé pour présenter en saisie par d’une fiche exemple : - une date dans une donnée de travail sous forme jjmmaa alors qu’elle est sous forme aaaammjj dans le fichier. - Découper en saisie un identifiant comme le code banque en une seule partie dans le fichier. - Etc…. Notons dans ce cas que le préaffichage seul ne suffit pas. Il convient également de contrôler les données de travail en saisie mais aussi de remettre les données de travail dans les données du fichier avant la mise à jour effective. Nous devrons donc placer des instructions ILE RPG respectivement dans trois sous-programmes : SRPRP_2 : préparation en non(création) SRWFCHn : contrôle de la fiche n= page 1..9 SRCHGF_2 : mise à jour fichier. Notons que nos générateurs ont un raccourci qui permet de traiter une donnée de travail numérique pour la date en une seule finition SHORTWAY qui regroupe le préaffichage en non(création), le contrôle, et peupler la date fichier avant la création ou la mise à jour effective. 40 41 CHAPITRE II Personnaliser les programmes II.4 ) Finition développée par le générateur Comment visualiser une finition développée par un générateur ? Comment effacer une finition ? Peut-on ajouter une finition à un contrôle manuel ? Ce paragraphe II.3 a pour objet de répondre à ces questions. Visualiser ou Effacer Finition Pour visualiser/effacer une finition d’un générateur, sélectionner le champs d’Entrée/Sortie qui a fait l’objet d’un préaffichage ou d’un contrôle. Nous prendrons comme exemple la finition SHORTWAY d’une date qui effectue un préaffichage jjmmaa + un contrôle date+ une mise dans le fichier aaaammjj avant mise à jour fichier : Adresse lgn 3. Code Postal. . Ville. . . . . Date . . . . . . . . . . . . . . . . . .: .: .: .: BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB BBBBB BBBBBBBBBBBBBBBBBBBBBBBBBB 99/99/99 Positionner le curseur et sélectionner le champ date. ENTRE FINITIONS POUR: WDTE Date 1=Sélection pour ajout règles de gestion F09 ou F12=DESIGN A_PREAFC (Avant saisie) Pré-affichage en CREATION A_PREAFU (Avant saisie) Pré_affichage en NON(CREATION) B_F04 (Aider saisie) F4 sur champ; Appel pgm de sélect C_CONTROL (Pendant saisie) Appliquer une règle ; contrôler D_FILE (Après saisie) Renseigner les champs / fichier SHORTWAY RACCOURCI : Préaf. Ecran + Contrôle + ->Fichier _____________________HISTORIQUE_________________________________ 4=Supprimer règle historique 5=Voir RPGLE si Gen=1 Gen 4 SHORTWAY SHORTDATE RACCOURCI DATE: Préaf. Ecran + Ctrl + 1 Le code génération = 1 de la finition SHORTWAY signifie que le ILE RPG a été inséré dans le source cible. Saisir ‘4’ pour supprimer le code. 41 42 CHAPITRE II Personnaliser les programmes II.4 ) Visu ou effacer finition 193.00 194.00 195.00 311.00 312.00 313.00 314.00 315.00 316.00 317.00 318.00 319.00 Y001 C PARM WMsgId Y001 C PARM WMsgDta --------------------------------------------------------Y001 C* Y001 C* Conversion date : Date Y001 C MOVEL(p) C1DTCTUT WDATE Y001 C EVAL WFrmFmt = '*YYMD' Y001 C EVAL WToFmt = '*DMY' Y001 C EVAL WToSep = '*NONE' Y001 C CLEAR WMsgId Y001 C CALL 'WCVTDAT' WCvtDat Y001 C* Le source généré de la finition est affiché. F09 pour valider la suppression ou F11 pour accéder au source via SEU. Notons les points suivants : - Y001 est le code historique de la finition juste devant la carte C en position 1 à 4. A chaque finition, le code historique est incrémenté de 1 pour le programme. Seules les lignes du source qui contiennent ce code historique ET dont la date est égale à la date de génération sont affichées et seront supprimées. - Le trait séparateur ------ signifie que le générateur a développé la finition dans deux sous-programmes différents. - La ligne nnn.00 correspond à la ligne dans le source ILE RPG. Il suffit donc de noter le numéro de la ligne puis F11=SEU pour accéder à une finition via SEU. - Notons que nos générateurs utilisent une routine de conversion et contrôle de dates plutôt que les instructions ILE RPG relatives aux dates. En effet, ce programme CL WCVTDAT peut être modifié pour traiter les cas particuliers qui existent dans certaines sociétés, comme les dates initialisées à zéro dans les fichiers ou encore les dates initialisées à 99999999. De plus le contrôle date est homogène et ne bloque pas l’écran comme le contrôle d’une donnée de type date contrôlée directement par le système i5 avant de passer la main au programme. 42 43 CHAPITRE II Personnaliser les programmes II.4 ) Finition Peut-on mixer finitions par le générateur et finitions spécifiques ? développée Peut-on modifier manuellement une finition ? par le générateur et manuellement Revenons à notre exemple du chaitre II.2 ajout manuel d’un contrôle relatif au code postal et à la ville. Ajouter le contrôle suivant avec le générateur : Tout caractère du code postal doit être soit blanc, soit A..Z, 0..9 Le générateur va ajouter juste avant le tag End_IN16P1 le contrôle : C* C* ind. erreur = 16 C1CODPOS Code Postal C IF (C1CODPOS <> *BLANK OR C C1VILLE <> *BLANK) C AND C (C1CODPOS = *BLANK OR C C1VILLE = *BLANK) C EVAL *IN16 = *ON C EVAL *IN17 = *ON C EVAL WMsgf = 'ABCMSGF' C EVAL WMsgId = 'ABC0001' C CALL 'WSNDMSG' WSndMsg C ENDIF C* C* Autorisé A..Z ; 0..9 : Code Postal C* caractère blanc admis (mais champ > blanc). C EVAL WBLOK = '1' C* C IF C1CODPOS = *BLANK C EVAL *IN16 = *ON C EVAL WMsgId = 'USR0003' C EVAL WMsgF = WMsgFSys C CALL 'WSNDMSG' WSndMsg C ENDIF C* C MOVEL *HIVAL WFFDAZ09 C MOVEL C1CODPOS WFFDAZ09 C CALL 'WCRAZ09' WCRAZ09 C* C IF WAZ09OK = *OFF C EVAL *IN16 = *ON C EVAL WMsgId = 'USR0016' C EVAL WMsgF = WMsgFSys C CALL 'WSNDMSG' WSndMsg C ENDIF C* C End_IN16P1 tag Il suffit maintenant de supprimer manuellement les lignes en vert, générées en trop, car C1CODPOS peut être à blanc entièrement. Nous pouvons donc travailler main dans la main avec le générateur en ILE RPG. Nous ne distinguons plus, sur le plan qualitatif, ce qui a été généré automatiquement de ce qui a été généré manuellement. 43 44 CHAPITRE II Personnaliser les programmes II.5 ) Sousfichiers Comment charger le sous-fichier en total afin par exemple d’afficher une totalisation des lignes commandes dans une donnée de travail d’entête du sousfichier ? C SRCharge BEGSR C CLEAR WCurLinWrt C* C* Ligne courante < nbre de lignes dans une page écran C DOW NOT %EOF(EXCLIENTL1) C************ AND WCurLinWrt < WSflPag C* C* Lectures détail ET préaffichages éventuels. C EXSR SRDtlRead C ADD 1 RRN C ADD 1 WCurLinWrt C CLEAR WOpt C WRITE WSFL C* C* EXCLIENTL1 Client par Pays C EXCLIEN001 READE(n) EXCLIENTR C ENDDO 1°) Pour charger le sous-fichier en total, mettre en commentaire la ligne en vert (ET ligne courante < nombre de ligne par page). Ainsi, le fichier ou le groupe sera lu entièrement. 2°) Après l’instruction CLEAR mettre à zéro la donnée de travail 3°) Dans le sous programme SRDTLREAD qui regroupe les lectures détail et les préaffichages, totaliser la colonne dans la donnée de travail qui sera affichée au niveau de l’entête. ==================================================== Comment forcer le chargement du sous-fichier ? Remarque : le rafraichissement de l’écran est obtenu en activant F05. Soit : C* C C F05 réafficher : WHEN CLEAR KeyPress = F05 WSflRcdNbr Il suffit de mettre à zéro la variable WSFLRCDNBR. Au niveau de l’algorithme général, si cette valeur est à zéro, un chargement du sous-fichier sera effectué : C C C* C* C C* C* C C* C* C C* C* C C* C DOW NOT(KeyPress = F03) AND NOT(KeyPress = F12) Charger sous-ficher si rang courant = 0 OU 'A partir IF WSflRcdNbr = *ZERO OR *IN97 Mise à blanc du sous-fichier: EXSR SRClrSfl 1ER positionnement fichier : EXSR SR1rstRead Chargement du sous-fichier page suivante : EXSR SRCharge ENDIF 44 45 CHAPITRE II Personnaliser les programmes II.5 ) Sousfichiers Comment sont gérées les touches de fonction dans les programmes transactionnels ? Définition de la variable KeyPress et F01..F24. La variable KEYPRESS et les constantes des fonctions sont définies dans un membre en /COPY : D* Variables Système D/COPY COPYF,COPYM et INFDS fichier écran Contenu de ce member source commun aux programmes en /COPY: * INFDS niveau écran : DDS_DISPLAY DS DKeyPress 369 369 DCursorLoc 370 371B 0 * Touches de fonction, valeurs de KeyPress DF01 C X'31' DF02 C X'32' DF03 C X'33' DF04 C X'34' DF05 C X'35' DF06 C X'36' DF07 C X'37' DF08 C X'38' DF09 C X'39' DF10 C X'3A' DF11 C X'3B' DF12 C X'3C' DF13 C X'B1' DF14 C X'B2' DF15 C X'B3' DF16 C X'B4' DF17 C X'B5' DF18 C X'B6' DF19 C X'B7' DF20 C X'B8' DF21 C X'B9' DF22 C X'BA' DF23 C X'BB' DF24 C X'BC' DEnter C X'F1' DHelp C X'F3' DRollUp C X'F5' DRollDown C X'F4' D*** Print C X'F6' 45 46 CHAPITRE II Personnaliser les programmes II.5 ) Sousfichiers Remarque : l’INFDS retourne une valeur hexa à chaque foins que l’utilisateur appuie sur une touche de fonction. Par exemple, si l’utilisateur appuie sur entrée, la variable KEYPRESS prendra la valeur hexa ‘F1’. Nous pouvons donc écrire en ILE RPG : C IF KeyPress = x’F1’ Ce qui ne serait pas très lisible. C’est pourquoi nous avons défini autant de constantes hexa qu’il y a de touches de commandes afin de pouvoir écrire l’équivalent : C IF KeyPress = Enter A retenir : Il est tout à fait possible de forcer dans le programme la valeur de KeyPress en cas de besoin. Ainsi, si l’appuie de la touche F12=Précédent est équivalente à la touche F09=Valider, nous pourrons avoir : C IF …………………………………………….. C EVAL KeyPress = F12 or KeyPress = F09 KeyPress = F09 Ce qui simplifiera la logique du traitement si l’utilisateur appuie sur F12, car F09 est forcé plus loin afin de traiter l’équivalence. Autre exemple : C …………………………………………. C IF ERREUR = *ON EVAL KeyPress = F03 En cas d’erreur grave, la sortie de travail est traitée en simulant F03=Sortie par l’utilisateur, ce qui simplifie la logique du traitement. Note : la touche PRINT est laissée en commentaire par défaut. 46 47 CHAPITRE II Personnaliser les programmes II.6 ) Editions : Rappel : Les éditions partent des clés du fichier principal appelé fichier primaire. Ces clés peuvent être soit les clés naturelles du PF ou LF, soit les clés issues d’un OPNQRYF. De ces clés, il faudra sélectionner les ruptures éventuelles de 9 à 1, sachant que plusieurs clés peuvent partager le même niveau de rupture. Principe des éditions : PRTF : Il y aura autant de formats Entête et de formats Pied qu’il y a de ruptures. ILE RPG : Il y aura autant de sous-programmes Entête et de sousprogrammes Pied qu’il y a de ruptures. Il est important de constater que : L’algorithme dépend des ruptures déclarées. Chaque Format entête ou pied du PRTF ou sous-programme entête ou pied du ILE RPG peut être vide. S’il est vide, l’écriture du format vide est effectué (sans effet sur l’impression). Donc, en maintenance un format entête ou pied vide pourra toujours être peuplé par la suite au besoin. Les ruptures déterminent également une présentation des éditions. Outre les ruptures, il y a également un format entête début programme, un format pied fin de programme ainsi qu’un format 1ère page. Notons qu’un format spécial sera imprimé à chaque saut de page sur les premières lignes de la page suivante indépendamment de l’algorithme. Ce format peut être paramétré pour votre société : SEU_hlp Manage Système OS/400 ____________________ ________________________________ io V6.3 FAST Environnement temporaire : ARC_USR/QRPGLESRC Paramétrer ergonomie ____ ---- ERGONOMIE / =Sélection Opérations et Fonctions Attribut clés ergonomie classique os/400 Attribut clés ergonomie menu déroulant Présentations de la box Titre pour critères de sélection Entête standard EDITION /début page Fonction SFLDROP Il vous suffit alors de choisir une édition type en saisissant le fichier et membre source du PRTF modèle. A chaque création, le générateur va copier ce format de début à chaque saut de page. 47 48 CHAPITRE II Personnaliser les programmes II.6 ) Editions : Voici ci-après la structure type d’un programme d’édition PRT avec 9 niveaux de ruptures maxi. Obtenu avec : /SEU/ « Sous-programmes du modèle. » Début Programme | Début rupture L9 | | Début rupture L8 | | | Début rupture L7 | | | | Début rupture L6 | | | | | Début rupture L5 | | | | | | Début rupture L4 | | | | | | | Début rupture L3 | | | | | | | | Début rupture L2 | | | | | | | | | Début rupture L1 | | | | | | | | | | Détail | | | | | | | | | Fin rupture L1 | | | | | | | | Fin rupture L2 | | | | | | | Fin rupture L3 | | | | | | Fin rupture L4 | | | | | Fin rupture L5 | | | | Fin rupture L6 | | | Fin rupture L7 | | Fin rupture L8 | Fin rupture L9 Fin de programme KLIST Edition | | | | | | | | | | | | | | | | | | | | | | SRFRSTPG SRBEG_L9 SRBEG_L8 SRBEG_L7 SRBEG_L6 SRBEG_L5 SRBEG_L4 SRBEG_L3 SRBEG_L2 SRBEG_L1 SRDETAIL SREND_L1 SREND_L2 SREND_L3 SREND_L4 SREND_L5 SREND_L6 SREND_L7 SREND_L8 SREND_L9 SRENDPGM_F SRKLIST ================================================== Retenir : Différence entre un PRTF et un DSPF : Le fichier PRTF est un fichier d’impression qui ressemble à un DSPF avec les particularités suivantes : -) Le numéro de ligne est facultatif. Le passage à la ligne suivante s’effectue lorsque le mot clé SPACEB(n) est rencontré, le passage à la page suivante lorsque le mot clé SKIPB(n) est rencontré, lors de l’écriture du format, n étant un nombre compris entre 1 à 9. (Saut de 1 à 9 lignes avant l’écriture). -) L’écriture des lignes s’effectue séquentiellement jusqu’à atteindre la valeur de l’overflow déduction faite du nbre lignes / pied édition. Saut de page au niveau du générateur : Le mot clé SKIPB(1) saut de page est présent dans un seul format du PRTF : A A R WSKIPB1 SKIPB(1) Lorsque ce format est écrit, une page est sautée. 48 49 CHAPITRE II Personnaliser les programmes II.6 ) Editions : Ecritures ENTETE différées : L’écriture ENTETE est retardée au tout dernier moment et est effectuée lors de l’écriture de la ligne détail. Ainsi, une rupture d’ overflow ne peut pas se cumuler avec une rupture où il y a un saut de page. En effet, l’indicateur Wnew=saut de page peut être mis plusieurs fois à *ON, avec dans tous les cas un seul saut de page au tout dernier moment. Pour les mêmes raisons, les écritures ENTETE sont différées au tout dernier moment : WW_BL1=*ON mis à *ON une ou plusieurs fois. C* Début L1 Code Pays C SRBEG_L1 BEGSR C* C* CLIPAYS Pays C MOVEL(p) C1PAYS C3CODPAYS C *NOKEY CLEAR *ALL CLIPAYSR C CLIPAYS001 CHAIN CLIPAYSR C* C* Nouvelle page pour saut de page indirect C EVAL WNew = *ON C* C* Ecriture indirecte format PRTF C1PAYS Code Pays C EVAL WW_BL1 = *ON C ENDSR ================================================== INFDS et l’overflow : F* Fichier PRTF : FPRTPGMEDITO E F …………………………………………….. DDS_Printer D WRows D WColimns D WOverFlow D WCurLine D WCurPage D* PRINTER INFDS(DS_Printer) DS 152 154 188 367 369 153B 155B 189B 368B 372B 0 0 0 0 0 L’INFDS du PRTF DS_Printer permet de récupérer la ligne courante, la page courante, la position exacte de l’impression mais aussi l’Overflow. La valeur de l’Overflow peut être changée par un CHGPRTF. Ceci étant, le CHGPRTF est fortement déconseillé : en cas de recompilation du PRTF, toutes les paramètres modifiés sont perdus. En cas de modification des valeurs par défaut du PRTF, il convient de créer un CL en amont avec une commande OVRPRTF suivi de l’appel du programme d’édition. 49 50 CHAPITRE II Personnaliser les programmes II.6 ) COLHDG : Nos générateurs reprennent les COHLDG des PF et LF en tant que sous-titres. Très souvent les COLHDG n’ont pas été saisis avec soin lors de la création initiale du fichier PF. Comment modifier les COLHDG d’un source DDS sans recompiler les PF et les LF ? Procéder comme suit : 1°) Modifier le membre source du PF (ou le répertoire) en ne modifiant que COLHDG et le texte. Conseil : mettre un ou deux niveaux de sous-titre en faisant bien attention à la longueur du champ. Le sous-titre ne doit pas trop dépasser cette longueur. Ne pas oublier que les COLHDG seront utilisés également par les QRY. A A A A A A A A A R EXCLIENTR C1KCLI C1RAISON C1ADR1 C1ADR2 C1ADR3 C1CODPOS C1VILLE C1PAYS 6 32 32 32 32 5 26 3 0 COLHDG('Clé' 'Client') COLHDG('Raison' 'Sociale') COLHDG('Adresse' 'lgn 1') COLHDG('Adresse' 'lgn 2') COLHDG('Adresse' 'lgn 3') COLHDG('Code' 'Postal') COLHDG('Ville') COLHDG('Clé' 'Pays') 2°) Lancer la commande CHGPF en précisant l’emplacement du fichier source et du membre source. CHGPF FILE(ARCHIPES/EXLIENT) SRCFILE(TSTLIBSRC/QDDSSRC) Les COLHDG seront pris en compte pour l’objet *file PF. Il sera également modifié pour tous les LF dépendants qui partagent le même format que le fichier physique. 50