1 FLOT DE COMMANDES (non utilisé aujourd'hui sauf cas particuliers) ------------------- Le flot de commandes peut être stocké sur supports externes, disquette, disque. Il sera exécuté grâce à la commande STRxxxRDR ou xxx indique le support (DKT pour les disquettes et DB pour le disque). Les instructions utilisées dans ce "programme" seront les commandes IBM ou celles que vous aurez crées. Le flot de commandes commencera toujours par l'instruction : // BCHJOB et finira par : // ENDBCHJOB EXEMPLE : |
2 PROGRAMME COMPILE ------------------- On parlera, pour cette utilisation, de programme en langage de contrôle. Un programme en langage de contrôle comportera donc une codification source, cette codification sera effectuée grâce à SEU (Option 2 sous PDM/AMT ou F6 pour créer) avec le TYPE CLP (Control Language Program). Le source doit être placé dans le fichier source QCLSRC, par défaut. Un programme devra commencer par l'instruction : PGM et se terminer par l'instruction ENDPGM, remarques : les lignes à blanc sont acceptées les commentaires sont notés /* commentaire */ ou bien /* autre + commentaire */ |
un programme compilé, accepte les invites sélectives
Gestionnaire de développement - PDM (STRPDM / STRAMT) |
Sélection des membres |
PDM - Gestion des membres |
Colonnes . . .: 1 71 Edition SOURCE/QTXTSRC SEU=> TEST FMT ** ...+... 1 ...+... 2 ...+... 3 ...+... 4 ...+... 5 ...+... 6 ...+... 7 ************** Début des données *********************************** ''•'''' ''''''' <- saisissez un caractère de contrôle : |
Un programme en langage de contrôle comporte 2 parties : une partie déclarative et une partie traitement. 2.1 DECLARATIVES ---------------- La partie déclarative sert à déclarer les variables utilisées par votre programme et les fichiers utilisés lors de traitement spécifique sur un écran ou un fichier base de données. 2.1.1 DECLARATION DE VARIABLE ----------------------------- Un programme qui utilise des variables doit indiquer leur longueur et leur type. Pour déclarer une variable nous indiquerons la commande DCL. |
Exemple: DCL VAR(&CTR) TYPE(*DEC) LEN(4 0) VALUE(1000) ! ! ! ! ! ! ! ! ---------------------- ! ------------------------- ! !Dans ce paramètre ! Celui-ci définira sa ! !nous indiquerons le ! longueur. Une seule ! !nom de la variable, ! valeur pour les variables ! !qui doit toujours ! alphanum. (9999 maxi) et ! !commencer par le ! 2 pour le numérique ! !caractère & ! (15 9 maxi) ! ! ! ------------------------------------- --------------------------- !Dans celui-ci nous indiquerons ! ! ce paramètre sert à ! !le type. 6 valeurs sont possibles: ! ! définir une valeur ! ! *DEC numérique packé ! ! initiale à la variable.! ! *CHAR alphanumérique ! ! Il est, bien entendu, ! ! *LGL logique ou booléen('0'/'1')! ! facultatif ! ! *INT binaire signé (V5R30) ! ! *UINT binaire non signé (V5R30) ! |
2.1.1 DECLARATION DE FICHIER ---------------------------- Utile quand vous voulez lire un fichier, il n'est pas nécessaire de déclarer les fichiers que vous utilisez dans des commandes de copie, de remise à blanc, etc... Pour le déclarer vous utiliserez la commande DCLF. Exemple: DCLF FILE(*LIBL/FIC1) RCDFMT(FOR1) OPNID( ) ! ! ! ---------------------- ! ! Dans ce paramètre vous ! Pour ouvertures multiples indiquerez le nom du ! en V5R30. fichier à utiliser, ! ainsi que sa bibliothèque ! ----------------------------------------- Dans celui-ci vous indiquerez le ou les formats utilisés (max. 50). Si vous voulez les utiliser tous, vous indiquerez *ALL (valeur par défaut) |
...................................................................... :Sachez qu'il est possible, pour toutes les commandes du langage de : :contrôle, de demander l'invite de la commande en utilisant F4. : :....................................................................: ATTENTION: Quand vous déclarez un fichier, le compilateur va déclarer automatiquement les zones de votre format. Vous pourrez utiliser ces zones en indiquant leur nom externe, précédé du caractère & . Toutes les variables du langage de contrôle commencent par &. 2.2 TRAITEMENTS --------------- Dans cette partie vous indiquerez les instructions à exécuter. Vous pourrez effectuer des calculs, des comparaisons, des déplacements de zone, des déplacements d'une partie de zone etc.... |
2.2.0 CHGVAR ------------- Permet de modifier une variable (ici &A) CHGVAR VAR(&A) VALUE(0) /* mettre 0 dans A */ CHGVAR VAR(&A) VALUE(&B) /* mettre B dans A */ 2.2.1 CALCULS ------------- La plupart des opérations arithmétiques sont possibles en langage de contrôle. Supposons l'addition A = A + 2 Pour faire cette addition j'utilise la commande qui permet d'affecter une nouvelle valeur à une variable. |
CHGVAR VAR(&A) VALUE(&A + 2) ! ! ! ! ! ! ------------------ ! ------------------------ Instruction qui ! Nouveau contenu de la permet de changer ! variable. Ici le résultat le contenu d'une ! d'une addition. variable. ! ------------------ Variable dont le contenu doit être changé Cette commande CHGVAR peut être utilisée pour affecter une constante à une variable, on l'utilisera à chaque fois que l'on voudra changer le contenu d'une variable. |
On peut effectuer des calculs complexes grâce à cette commande. Sachez que pour indiquer une addition on indiquera : + une soustraction : - une division : / une multiplication : * B + C - 3 exemple : A = ---------- X ---------- (Z - 3)* 5 S'écrira : CHGVAR VAR(&A) VALUE((&B +&C -3) / (&X / ((&Z - + 3)*5))) ^ | ------------------ + signifie que la commande continue ligne suivante . |
2.2.2 LA CONCATENATION ---------------------- CHGVAR VAR(&DEPART) VALUE(&HH *CAT &MM *CAT &SS) Il est de possible de regrouper plusieurs zones entre elles. Pour cela nous utilisons l'instruction *CAT . Si nous voulons regrouper des zones entre elles, en insérant 1 blanc entre chaque zone, nous utilisons *BCAT. Si nous voulons supprimer les blancs de droite de la première zone nous utilisons *TCAT. PGM DCL VAR(&A) TYPE(*CHAR) LEN(6) VALUE('BON ') DCL VAR(&B) TYPE(*CHAR) LEN(6) VALUE('JOUR ') DCL VAR(&C) TYPE(*CHAR) LEN(12) -------CHGVAR VAR(&C) VALUE(&a *CAT &b) ! CHGVAR VAR(&C) VALUE(&a *TCAT &b)---------------- ! ! ------> la variable &C aura le contenu 'BON JOUR ' ! ! la variable &C aura le contenu 'BONJOUR ' <----- |
La commande OPNQRYF utilisait beaucoup la concaténation OPNQRYF CLIENTS QRYSLT('depcli = 44'), placée avant l'appel à un pgm RPG utilisant le fichier CLIENTS, fait que ce dernier ne "voit" que les clients du département 44. Pour réaliser cela avec la variable &DEP (*CHAR 2) OPNQRYF CLIENTS QRYSLT('depcli = ' *CAT &DEP) Pour faire une sélection sur la ville il faut écrire OPNQRYF CLIENTS QRYSLT('vilcli = "PARIS" ') le caractère ' marque le début et la fin de la sélection le caractère " " " " " " " de CHAQUE constante OPNQRYF OPNQRYF CLIENTS QRYSLT('vilcli = "' *cat &VILLE *cat '"') ou CHGVAR &SELECT VALUE('vilcli = "' *cat &VILLE *cat '"') OPNQRYF CLIENTS QRYSLT(&SELECT) |
2.2.3 L'EXTRACTION ------------------ Nous pouvons aussi extraire d'une chaîne de caractères, certains des caractères qui la composent, ceci grâce à l'instruction %SST (ou %SUBSTRING) PGM DCL VAR(&A) TYPE(*CHAR) LEN(15) VALUE('BON APPETIT') DCL VAR(&B) TYPE(*CHAR) LEN(7) /* */ /* JE VEUX PLACER LA VALEUR APPETIT DANS LA VARIABLE &B */ /* */ CHGVAR VAR(&B) VALUE(%SST(&A 5 7)) ! ! !-----! ---------------- ! ! modif. d'une ! ! variable ---------------- ! extraction d'une --------------------------- sous-chaîne de Variable extraite depuis la caratères position 5 sur 7 caractères |
Il est possible de ne modifier qu'une partie d'une variable : PGM DCL VAR(&A) TYPE(*CHAR) LEN(15) VALUE('BON APPETIT') DCL VAR(&B) TYPE(*CHAR) LEN(15) VALUE('JOYEUX NOEL') CHGVAR VAR(%SST(&B 8 7)) VALUE(%SST(&A 5 7)) La partie VALUE du CHGVAR peut comprendre des sous-chaînes concaténées. CHGVAR VAR(&A) VALUE(%sst(&B 1 2) *CAT %sst(&C 3 2)) Exemple : PGM DCL VAR(&STAG) TYPE(*CHAR) LEN(10) VALUE('FORMATION1') DCL VAR(&BD) TYPE(*CHAR) LEN(10) VALUE('BDVIN') CHGVAR VAR(%sst(&BD 6 1) VALUE(%sst(&STAG 10 1) ADDLIBLE &BD /* Ajout de BDVIN1 */ |
2.2.4 LES OPERATIONS LOGIQUES ----------------------------- En langage de contrôle il est possible d'effectuer des comparaisons entre deux variables, ou entre une variable et une constante, et suivant le résultat de cette comparaison déclencher une action. Supposons le test suivant si A > B appeler le prog. PROGA, sinon appeler le prog. PROGB Cela s'écrira en langage de contrôle : IF COND(&A *GT &B) THEN(CALL PGM(PGMA)) ELSE CMD(CALL PGM(PGMB)) |
Reprenons l'instruction IF et détaillons-la : IF COND(&A *GT &B) THEN(CALL PGM(PGMA)) ! ! ! -------------- ! --------------------------- instruction de ! on place ici l'instruction comparaison ! à exécuter si la condition ! est remplie ------------------ Opérateur relationnel *GT ( > ) *GE ( >= ) *LT ( < ) *LE ( <= ) *EQ ( = ) *NE ( ^= ) |
on peut donner des conditions complexes avec *AND ( & ) *OR ( ! ) *NOT ( ^ ) sous la forme : IF COND((&A *EQ 0) *OR (&x *LT &Y)) THEN( ...) Attention sur l'invite il faut saisir toutes les parenthèses : si (IF) condition . . . . . . . . . . ((&a *eq 0) *or (&x *lt &y)) |
Continuons avec ELSE : ELSE CMD(CALL PGM(PGMB)) ! ------------------------- instruction à réaliser si la condition n'est pas remplie Supposons, si la condition est remplie, que je veuille exécuter plusieurs commandes, je ne peux placer qu'une seule instruction derrière THEN. Pour cela j'utiliserai les commandes DO et ENDDO. EX: si A > B alors appel PGMA1 PGMA2 PGMA3 sinon appel PGMB1 PGMB2 PGMB3 |
IF COND(&A *GT &B) THEN(DO)--> début des instructions CALL PGMA1 CALL PGMA2 CALL PGMA3 ENDDO --> marque la fin des instructions à exécuter ELSE CMD(DO) CALL PGMB1 CALL PGMB2 CALL PGMB3 ENDDO On peut aussi utiliser des IF imbriqués (peu lisible) IF ------- THEN(IF ------ THEN(IF_____THEN(___) ... ) |
LES BRANCHEMENTS INCONDITIONNELS -------------------------------- A tout moment dans un programme CL il est possible de se débrancher à une autre séquence d'instruction. Supposons le programme d'enchaînement des tâches suivant : - exécution de PGMA - tant que A = B exécution de PGMB et PGMC - exécution de PGMD S'écrira : CALL PGM(PGMA) ENCORE: CALL PGM(PGMB) ^ CALL PGM(PGMC) ! IF COND(&A = &B) THEN(GOTO ENCORE) ! CALL PGM(PGMD) ! ! ------------------------------------ -------------------- GOTO instruction de débranchement définition d'une inconditionnel. A comme paramètre une étiquette étiquette qui indique l'endroit où se débrancher |
La version 5.30 de l'OS/400 apporte de nombreuses améliorations au CL. particulièrement les boucles (Do-While et Do-Until) et l'ordre Select. Nous avons donc, maintenant : DOWHILE COND( même test que sur un IF) ... ENDDO c'est un vrai dowhile, le test est réalisé avant (on peut ne jamais entrer dans la boucle) et il s'agit de la condition pour FAIRE DOUNTIL COND( même test que sur un IF) ... ENDDO pour dountil, le test est réalisé sur le ENDDO (on fait au moins une fois) et la condition donnée est celle pour SORTIR. |
DOFOR VAR(&cpt) FROM(1) TO(22) BY(3) ... ENDDO pour ces trois boucles on peut forcer - une sortie anticipée par LEAVE sans paramètre, on sort de la boucle en cours (la dernière) on peut mettre un LABEL devant le DOxxx et indiquer le label sur le LEAVE - un saut d'un tour de boucle par ITERATE et enfin, l'équivalent du CASE SQL ou du SELECT RPG : SELECT WHEN COND( ) THEN( ) /* seul le premier test vrai est traité */ WHEN COND( ) THEN() OTHERWISE CMD( ) ENDSELECT |
Pour finir, la V5R40 propose maintenant la notion de sous programme - les sous programmes doivent être placés en FIN de pgm - un sous programme peut lancer un sous programme (99 niveaux possibles) exemple de source CL avec sous programme PGM DCL &V1 *CHAR LEN(20) DCL &rt *INT LEN(4) ############################### # # .../... # La notion de valeur retour # # est facultative # CALLSUBR SUBR(TEST) RTNVAL(&RT) # # # Si vous l'utilisez il doit # # s'agir d'une variable *INT # /* fin logique du pgm */ # sur 4 octets. # SUBR SUBR(TEST) # # ############################### .../... ENDSUBR RTNVAL(&rt) |
Après les fonctions intégrées suivantes : %SST extraction d'une chaîne de caractères %BIN extraction et conversion d'une sous-chaîne en binaire %SWITCH manipulation des switchs du job (concept d'origine 36) %OFFSET manipulation d'un pointeur (incrémentation/déplacement) %ADDRESS assignation d'un pointeur avec l'adresse d'une variable La PTF SI48166 (V7) propose %TRIM élimination des blancs d'extrémité d'une chaîne %TRIMR élimination des blancs de droite %TRIML élimination des blancs de gauche La PTF SI49061 (V7) propose %CHECK vérification des caractères d'une variable(gauche->droite) %CHECKR vérification des caractères d'une variable(droite->gauche) %SCAN recherche d'une chaîne dans une variable |
Enfin, en version 7.2 Fonctions de changement de genre %CHAR %DEC %INT %UINT Gestion de la casse %LOWER %UPPER Gestion de la taille des variables %LEN %SIZE Exemples : --------- CHGVAR VAR(&MSG) VALUE(%lower(&MSG)) CHGVAR VAR(&LG) VALUE(%len(&MSG)) |
3. RECUPERATION DES INFORMATIONS POUR LE TRAVAIL EN COURS. ---------------------------------------------------------- A tout moment dans un programme en langage de contrôle il est possible de connaître l'environnement du travail. à quelle OUTQ le travail est-il rattaché ? Quel est le profil utilisateur en cours ? etc... La commande qui nous permet cela est RTVJOBA. RTVJOBA JOB(&NOMJOB) USER(&NOMUSER) + OUTQ(&NOMOUTQ) .... /* on ne renseigne que les paramètres dont on a besoin */ RTVJOBA va placer le(s) paramètre(s) recherché(s) dans la/les variable(s) |
RTVJOBA JOB(variable qui recevra le nom du TRAVAIL) USER(variable qui recevra le nom du PROFIL utilisateur) NBR(variable qui recevra le NUMERO du travail) OUTQ(variable qui recevra le nom de l'OUTQ) TYPE(variable qui recevra le type batch/interactif) DATE(variable qui recevra la DATE) USRLIBL(variable qui recevra *LIBL) Supposons un programme qui ne peut être exécuté que par le profil COMPTA. Avant l'exécution, le programme contrôlera le profil utilisateur : PGM DCL VAR(&PROFIL) TYPE(*CHAR) LEN(10) RTVJOBA USER(&PROFIL) IF COND(&PROFIL *NE 'COMPTA') THEN(GOTO + CMDLBL(FIN)) ../.. FIN: ENDPGM |
Autre exemple avec recherche si bibliothèque est présente dans *LIBL avant de l'ajouter. ************** Début des données ********************************* PGM DCL VAR(&USRLIBL) TYPE(*CHAR) LEN(2750) DCL VAR(&POS) TYPE(*INT) LEN(4) DCL VAR(&USER) *CHAR(10) DCL VAR(&BIB) TYPE(*CHAR) LEN(10) VALUE(BDVIN) RTVJOBA USER(&USER) USRLIBL(&USRLIBL) CHGVAR VAR(%sst(&BIB 6 1) VALUE(%sst(&USER 10 1) CHGVAR VAR(&POS) VALUE(%SCAN(&BIB &USRLIBL)) IF COND(&POS = 0) THEN(DO) ADDLIBLE &BIB ENDDO ENDPGM *************** Fin des données ********************************** |
4. COMMENT UTILISER UN FICHIER EN CLP ------------------------------------- Dans un programme CLP il est parfois intéressant d'utiliser un fichier. Le langage CLP permet d'utiliser un fichier écran avec des opérations d'écriture ou de lecture, et les fichiers bases de données seulement en lecture. Pour cela nous devons d'abord les déclarer grâce à la commande DCLF : DCLF FILE(nom du fichier) RCDFMT(nom du ou des formats) + Cette commande permettra aussi de déclarer les zones du fichier automatiquement, avec des noms de zone commencant par &. Dans le cas de fichier écran il déclarera les indicateurs en tant que variables logiques et leur donnera un nom &INXX XX étant le numéro de l'indicateur utilisé. |
Les opérations d'E/S en langage de contrôle. 1 LECTURE --------- RCVF (RECEIVE FILE) RCVF DEV(*FILE) RCDFMT(nom du format) WAIT(*YES) N.B. Laissez les valeurs par défaut pour un fichier base de données. 2 ECRITURE (uniquement pour les fichiers écrans) ---------- SNDF (SEND FILE) SNDF RCDFMT(nom du format) |
2 ECRITURE PUIS LECTURE (uniquement pour les fichiers écrans) ----------------------- SNDRCVF (SEND RECEIVE FILE) SNDRCVF RCDFMT(nom du format) Exemple d'utilisation d'un fichier écran en langage de contrôle. Supposons une chaîne de traitements du soir que vous voulez lancer après le départ des utilisateurs. Pour cela l'opérateur devra appeler le CLP SOIRLANC et entrera l'heure de début de la chaîne. Le programme SOIRLANC affichera et lira le format HEURF1 du fichier HEURE. |
Utilisation d'un DSPF -------------------------------------------------------------- ! ! ! LANCEMENT DES TRAVAUX DU SOIR ! ! ! ! ! ! ! ! ! ! ! ! ! ! ENTRER L'HEURE DE DEBUT DE LA CHAINE __ __ __ ! ! (HH MM SS) ! ! ! ! ! ! ! ! ! ! ! ! F3 = Sortie. ! -------------------------------------------------------------- |
Codification du fichier écran --------------------------- |
Le programme SOIRLANC PGM DCL VAR(&DEPART) TYPE(*CHAR) LEN(6) DCLF FILE(HEURE) SNDRCVF RCDFMT(HEURF1) IF COND(&IN03) THEN(GOTO CMDLBL(FINCLP)) CHGVAR VAR(&DEPART) VALUE(&HH *CAT &MM *CAT &SS) SBMJOB JOB(ATTENTE) JOBD(SOIR) CMD(DLYJOB + RSMTIME(&DEPART) ) SBMJOB JOB(JOBSOIR) JOBD(SOIR) CMD(CALL PGM(SOIR)) FINCLP: ENDPGM Les fichiers en CL sont aussi souvent utilisés en lecture, suite à une commande plaçant un résultat dans un fichier de sortie. Exemple : DSPOBJD OBJ(mabib/*ALL) OBJTYPE(*PGM) OUTPUT(*OUTFILE) + OUTFILE(QGPL/LISTEPGM) Suite à cette commande, le fichier LISTEPGM peut être lu pour traitement. |
+ V5R30 : support de fichiers multiples Avant la V5R30, nous ne pouvions déclarer qu'un seul fichier par pgm ce qui fait qu'il n'était pas utile de préciser le nom . La v5r30 apporte un nouveau paramètre OPNID() sur les commandes DCLF RCVF, SNDRCVF, SNDF permettant de manipuler plusieurs fichiers. DCLF FILE(ECRAN1) OPNID(ECRAN) ........................................................................ : ATTENTION : les variables seront préfixées par l'OPNID suivi de "_" : : : : par exemple ce DSPF contient : : : : : JOB -> nommée dans le pgm &ECRAN_JOB : : Indicateur 3 -> nommé &ECRAN_IN03 : :......................................................................: l'OPNID est facultatif, mais un SEUL fichier peut ne pas en avoir, et nous sommes limités à 5 fichiers en tout, dans un même programme. |
les commandes de manipulation de fichier (SNDF, RCVF et SNDRCVF) doivent utiliser le paramètre OPNID s'il a été utilisé lors de la déclaration. exemple : --------- PGM DCLF FILE(QADSPOBJ) OPNID(OBJD) /* PF sortie DSPOBJD*/ DCLF FILE(ECRAN1) OPNID(ECRAN) BCL1: DOWHILE COND(*NOT &ECRAN_IN03) /* Tq pas F3 */ RCVF OPNID(OBJD) /* EOF */ MONMSG MSGID(CPF0864) EXEC(LEAVE CMDLBL(BCL1)) CHGVAR &ECRAN_ODOBNM &OBJD_ODOBNM /* PF vers DSPF */ CHGVAR &ECRAN_ODOBTP &OBJD_ODOBTP CHGVAR &ECRAN_ODOBTX &OBJD_ODOBTX SNDRCVF OPNID(ECRAN) /* affichage */ ENDDO ENDPGM |
3 SUBSTITUTION -------------- OVRDBF (OVERRIDE DATA BASE FILE) OVRPRTF (OVERRIDE PRINTER FILE) OVRDSPF (OVERRIDE DISPLAY FILE) Utilisée avant la première lecture (avant l'Open, donc), cette commande permet de travailler avec un autre fichier que celui prévu (déclaré) : DCLF FICHIER OVRDBF FILE(FICHIER) TOFILE(TOTO) RCVF (lit le fichier toto) ou avec le fichier prévu, mais avec des paramètres non standard. OVRDBF FILE(FICHIER) SHARE(*YES) /* obligatoire p. OPNQRYF */ OPNQRYF FICHIER QRYSLT('nocli > 50') |
Quelques exemples OPNQRYF : NOUS VOULONS SELECTER TOUS LES ENREGISTREMENTS DU FICHIER FICHA OU LA VALEUR DE LA ZONE CODE EST A. Le programme de traitement est PGMB OVRDBF FILE(FICHA) SHARE(*YES) --> paramètre SHARE(*YES) "forcé" |
Autre exemple, FTP en Batch. Passez les commandes suivantes dans un CL : OVRDBF FILE(INPUT) TOFILE(QTXTSRC) MBR(IN) OVRDBF FILE(OUTPUT) TOFILE(QTXTSRC) MBR(OUT) FTP RMTSYS(SERVEURx) Le membre IN (ou tout autre nom) doit contenir les commandes FTP : *** Début des données *** profil motdepasse CD bibli Put fichier QUIT *** fin des données *** il s'agit bien sûr d'un exemple, les commandes sont données à titre indicatif. :-) OUT recoit toutes les lignes qui auraient été affichées à l'écran. |
5. RECUPERATION DES MESSAGES D'ARRET --------------------------------- Un programme en langage de contrôle peut se terminer anormalement à l'exécution d'une commande. Si c'est le cas, un message est envoyé par le système au programme, ce qui provoque son arrêt. Si ce programme est une chaîne de traitements importants, il vaut mieux éviter l'arrêt pour des raisons bégnines. Exemples : - une chaîne est arrêtée lors de la commande CPYF, le fichier TOFILE est existant, et vous avez oublié de mettre la valeur *REPLACE dans le paramètre MBROPT. - ou bien, vous voulez vérifier l'existence d'un objet. S'il existe vous continuez le traitement, sinon vous le créez. (La commande à utiliser est CHKOBJ) Vous pourrez donc "monitorer" les messages (garder le contrôle), grâce à la commande MONMSG. ATTENTION cette commande ne monitore que les messages de type ERREUR |
La commande MONMSG MONMSG MSGID(CPFxxxx) N° du ou des messages à monitorer EXEC(la commande à exécuter si le message est récupéré) Exemple d'utilisation sur la vérification d'un objet. PGM /* vérification de l'existence du fichier de travail */ CHKOBJ OBJ(CLTTRA) OBJTYPE(*FILE) /* si le fichier n'existe pas je le créé + MESSAGE CPF9801 MONITORE */ MONMSG MSGID(CPF9801) EXEC( CRTDUPOBJ OBJ(MODELE) + OBJTYPE(*FILE) NEWOBJ(CLTTRA) ) /* lancement du pgm CLTPGM01 */ CALL CLTPGM01 /* Mise à blanc du fichier */ CLRPFM CLTTRA ENDPGM |
Il est possible de monitorer un groupe de message en indiquant une clé "générique" (plusieurs messages à la fois). MONMSG CPF2300 monitore les messages 2301 à 2399 MONMSG CPF0000 monitore les messages 0001 à 9999 ATTENTION si vous définissez vos propres messages ne jamais utiliser de numérotation multiple de 10 (MSG0000 ou MSG1000 etc...) Revenons sur notre exemple , nous avons utilisé le MONMSG après une commande, il sera pris en compte seulement pour la commande qui le précède (toute commande sauf une autre MONMSG (nous pouvons indiquer plusieurs MONMSG pour une même commande)). EX: CHKOBJ OBJ(CLTTRA) OBJTYPE(*FILE) /* ou toute autre commande */ MONMSG MSGID(CPF9801) EXEC(GOTO FIN) /* non trouvé */ MONMSG MSGID(CPF9802) EXEC(CALL PGMB) /* non autorisé */ MONMSG MSGID(CPFOOOO) EXEC(GOTO PRB) /* autre ... */ ---- |
Nous pouvons aussi monitorer un ou plusieurs messages sur l'ensemble des instructions du programme. Pour cela nous placerons la commande MONMSG avant la première commande exécutable, le paramètre EXEC dans ce cas, ne pourra contenir QUE L'INSTRUCTION GOTO. PGM DCL--- DCL--- MONMSG MSGID(----) EXEC(GOTO xxxx) ---- CALL FINDEMOIS ------ RETURN /* fin du pgm */ xxxx: ENDPGM La fin de fichier pour un fichier BD en lecture est signalée par le message CPF0864 , qu'il faut absolument prévoir. |
Exemple, lecture de LISTEPGM comme vu au dessus, pour destruction de tous les programmes (cde DLTPGM) ................................................................... : Liste des zones de LISTEPGM (DSPFFD pour le vérifier) : : : : - ODLBNM : Library name : : - ODOBNM : Object name : : - ODOBTP : Object type (comme *FILE, *PGM, ...) : : - ODOBAT : Object Attribut (comme PF, LF, PRTF, DSPF) : :.................................................................: PGM DCLF FILE(LISTEPGM) LECTURE: RCVF MONMSG MSGID(CPF0864) EXEC(GOTO FIN) /* fin de fichier */ DLTPGM PGM(&ODLBNM/&ODOBNM) GOTO CMDLBL(LECTURE) FIN: ENDPGM |
Exemple, lecture de LISTEPGM comme vu au dessus, pour destruction de pgm, avec réactualisation du fichier LISTEPGM PGM DCLF FILE(LISTEPGM) DSPOBJD OBJ(mabib/*ALL) OBJTYPE(*PGM) OUTPUT(*OUTFILE) + OUTFILE(QGPL/LISTEPGM) LECTURE: RCVF MONMSG MSGID(CPF0864) EXEC(GOTO FIN) DLTPGM PGM(&ODLBNM/&ODOBNM) GOTO CMDLBL(LECTURE) FIN: ENDPGM Mais deux personnes ne peuvent pas lancer le pgm en même temps, car les 2 utilisent le même fichier. Le mieux est alors d'utiliser la bibliothèque QTEMP qui est propre à chaque session ! |
PGM /* déclaration du modèle dans QSYS (voir l'aide du paramètre OUTFILE) */ /* pour pouvoir compiler (LISTEPGM n'existe pas encore dans QTEMP) */ DCLF FILE(QADSPOBJ) DSPOBJD OBJ(mabib/*ALL) OBJTYPE(*PGM) OUTPUT(*OUTFILE) + OUTFILE(QTEMP/LISTEPGM) /* Il ne faut pas lire QADSPOBJ qui est TOUJOURS vide */ /* mais LISTEPGM DE QTEMP ==> utilisation de OVRDBF */ OVRDBF FILE(QADSPOBJ) TOFILE(QTEMP/LISTEPGM) LECTURE: RCVF MONMSG MSGID(CPF0864) EXEC(GOTO FIN) DLTPGM PGM(&ODLBNM/&ODOBNM) GOTO CMDLBL(LECTURE) FIN: ENDPGM |
Exemple2 : Passage en HOLD(*YES) de tous les PRTFs de PAIE ET COMPTA PGM /* déclaration du modèle dans QSYS */ DCLF QADSPOBJ /* liste des fichiers de PAIE dans DSPOBJ1 */ DSPOBJD OBJ(PAIE/*ALL) OBJTYPE(*FILE) DETAIL(*FULL) + OUTPUT(*OUTFILE) OUTFILE(QTEMP/DSPOBJ1) /* liste des fichiers de COMPTA dans dspobj1 */ /* (cette liste vient s'ajouter au contenu actuel) */ DSPOBJD OBJ(COMPTA/*ALL) OBJTYPE(*FILE) + DETAIL(*FULL) OUTPUT(*OUTFILE) + OUTFILE(QTEMP/DSPOBJ1) OUTMBR(*FIRST *ADD) A suivre... |
/* attention je lis DSPOBJ1 à la place de QADSPOBJ */ OVRDBF QADSPOBJ QTEMP/DSPOBJ1 LECTURE: RCVF /* interception du message "fin de fichier" */ MONMSG CPF0864 EXEC(GOTO FIN) IF (&ODOBAT = 'PRTF') THEN(DO) /* attribut = type de fichier*/ /* traitement d'une ligne, si c'est un PRTF uniquement */ CHGPRTF FILE(&ODLBNM/&ODOBNM) HOLD(*YES) MONMSG CPF0000 /* en cas de problème, erreur ignorée */ ENDDO GOTO LECTURE FIN: /* tapez ici ce qui doit être fait une seule fois */ ENDPGM |
6. ENVOI DE MESSAGES ---------------------- Vous pouvez bien sur envoyer un message à un utilisateur (par ex. QSYSOPR) SNDMSG MSG('votre texte') TOUSR(leprofil) Ou sur un terminal en imposant une visualisation immédiate (BREAK) SNDBRKMSG MSG('votre texte') TOMSGQ(leterminal) Mais vous pouvez aussi envoyer un message au pgm qui a demandé le lancement de votre CL. Si celui contient une ligne de commande, vous verrez votre message sur la dernière ligne de l'écran une fois le pgm terminé . SNDPGMMSG MSG('votre texte') MSGTYPE(*INFO) |
Enfin vous pouvez poser une question par SNDUSRMSG (PGM CL uniquement) PGM |
Différents types de messages : ---------------------------- *INFO : une simple information *INQ : une question *COMP : Achevement => j'ai bien fait ce que je devais faire ! *DIAG : Diagnostique, en général suivi d'une erreur. *ESCAPE : Erreur provoquant l'arret du pgm. Un message d'erreur doit faire référence à un message venant d'un fichier message (pour pouvoir être monitoré) QCPFMSG contient un message CPF9898 pour vous aider, qui possède une seule variable, le texte à afficher. SNDPGMMSG MSGID(CPF9898) MSGF(QCPFMSG) MSGDTA('votre texte') MSGTYPE(*ESCAPE) *STATUS : Etat d'avancement, doit utiliser un ID message (CPF9897), apparait pendant le traitement si envoyé à *EXT. SNDPGMMSG MSGID(CPF9897) MSGF(QCPFMSG) MSGDTA('votre texte') TOPGMQ(*EXT) MSGTYPE(*STATUS) |
7. E N C H A I N E M E N T --------------------------- - Appel de programme. CALL - TFRCTL * CALL PGM(nom-du-programme) : le programme appelé s'exécute. A la fin de celui-ci, retour à l'instruction suivant le CALL dans le programme appelant. * TFRCTL PGM(nom-du-programme) : le programme appelé s'exécute. A la fin de celui-ci, retour à l'instruction suivant le dernier CALL exécuté. +---------+ A ! call B ! <--- +---------+ \ |
- Fin de programme : ENDPGM (doit être la dernière ligne du pgm) ou RETURN Retour immédiat à l'instruction suivant le CALL dans le programme appelant L'intéret de RETURN est qu'il peut être placé n'importe ou dans le source ........................................................................ : MONMSG CPFOOOO EXEC(RETURN) : : : : IF (&cpt > 999) THEN(RETURN) /* etc */ : : : :......................................................................: et bien sûr SIGNOFF Fin immédiate du Job. |
PASSAGE DES PARAMETRES ---------------------- Un programme CL peut être appelé par un programme écrit en n'importe lequel des langages, et peut donc recevoir des paramètres. Pour recevoir les paramètres nous les indiquerons dans la commande PGM. PGM PARM(&A &B etc....) Il ne faudra pas oublier de définir les paramètres reçus. Le programme retournera au programme appelant par l'instruction ENDPGM ou l'instruction RETURN, celui retrouvant ces paramètres, modifiés. ENDPGM et RETURN entraînent la désactivation du programme appelé. Un programme en CL peut bien sûr appeler un pgm et lui transmettre des données grâce a la commande CALL: CALL PGM(PGM1) PARM(&A &B etc...) |
PASSAGE DES PARAMETRES ---------------------- Attention aux passages de constantes. Sur AS/400 le passage de paramètres est un passage d'adresses. dans le cas de variables on passe l'adresse de la variable (pgm appelant) dans le cas de constantes, les constantes sont stockées dans un espace de travail et l'on passe cette adresse Mais quel espace réserver pour le stockage de ces constantes ??? Le CL a des valeurs par défaut, qui sont : APLHA si < à 32 ==> 32 octets sinon ==> la longueur exacte de la constante. NUMERIQUE ==> 15 dont 5 !!!! |
Quelques commandes utiles: RNMM : renomme un membre d'un fichier bases de données. RMVM : supprime un membre d'un fichier bases de données. ADDPFM : ajoute un membre à un fichier physique (bd ou source) DLYJOB : diffère le travail (fait une pause) CPYF : copie un fichier base de données. CPYSPLF : copie un spool dans un fichier PF ou dans l'IFS. RNMOBJ : renomme un objet. MOVOBJ : déplace un objet d'une bibliothèque vers une autre. CHGOBJD : change le texte d'un objet CHGOBJOWN : change le propriétaire d'un objet CRTDUPOBJ : duplique un objet (nom ou bibliothèque différent) RUNSQL : Exécute un ordre SQL (Version 7.1, tout sauf Select) |
Exemples de VALEURS SYSTEME (WRKSYSVAL pour avoir une liste) |
/*-------------------------------------------*/ /* PGM DE SAUVEGARDE DU SYSTEME */ /* ---------------------------- */ /* CE PGM DOIT ETRE LANCÉ À LA CONSOLE */ /* MOINS DE 24 HEURES AVANT L'HEURE PREVUE*/ /* LA CONSOLE EST ALORS INDISPONIBLE */ /*-------------------------------------------*/ PGM DCL &TYPDEJOB *CHAR 1 DCL &ECRAN *CHAR 10 DCL &CONSOLE *CHAR 10 DCL &ESSAI *DEC (3 0) RTVJOBA TYPE(&TYPDEJOB) /* ON DOIT ETRE EN INTERACTIF */ IF (&TYPDEJOB = '0') THEN(DO) SNDPGMMSG MSGID(CPF9898) MSGF(QCPFMSG) MSGDTA('Ce pgm + doit etre lancé en interactif') + MSGTYPE(*ESCAPE) RETURN ENDDO /* ET SUR LA CONSOLE (DSP01 ?) */ RTVJOBA JOB(&ECRAN) RTVSYSVAL SYSVAL(QCONSOLE) RTNVAR(&CONSOLE) |
Enfin, vous pouvez créer vos propres commandes : 1/ ajoutez un source dans QCMDSRC (HLDALLPRTF par ex.) 2/ saisissez les lignes suivantes CMD PROMPT('retenir tous les PRTF') PARM KWD(BIB) TYPE(*CHAR) LEN(10) MIN(1) + PROMPT('Bibliothèque à traiter') L'ordre CMD est unique et décrit la commande Il y a un ordre PARM par paramètre recu par le programme. - vous pouvez définir les memes types qu'en CL (plus d'autres) - MIN(O) le paramètre est facultatif, MIN(1) il est obligatoire 3/ compilez par CRTCMD CMD(HLDALLPRTF) PGM(votre_cl) Vous pouvez maintenant saisir HLDALLPRTF sur une ligne de commande et faire F4 . |
EXECUTION D'UNE COMMANDE VARIABLE DANS UN PGM CL ------------------------------------------------ IL EST POSSIBLE DANS PROGRAMME CL D'EXECUTER UNE COMMANDE CONTENUE DANS UNE VARIABLE (recue, lue dans un fichier, etc...) Il faut passer par l'intermédiaire d'un pgm système QCMDEXC Ce pgm attend deux paramètres 1/ la cde à exécuter 2/ la longueur du premier paramètre dans une variable *DEC (15 5) |
Soit un pgm qui reçoit + une zone option 1 = DSPFD /* infos générales sur un fichier */ 2 = DSPFFD /* liste des zones d'un fichier */ 3 = DSPPFM /* affichage brut du contenu */ + une zone fichier contenant le nom du fichier à traiter PGM PARM(&OPTION &FICHIER) DCL VAR(&COMMANDE) TYPE(*CHAR) LEN(50) DCL VAR(&LONGUEUR) TYPE(*DEC) LEN(15 5) VALUE(50) DCL VAR(&OPTION) TYPE(*CHAR) LEN(1) DCL VAR(&FICHIER) TYPE(*CHAR) LEN(10) IF COND(&OPTION = '1') THEN(CHGVAR VAR(&COMMANDE) VALUE('DSPFD')) IF COND(&OPTION = '2') THEN(CHGVAR VAR(&COMMANDE) VALUE('DSPFFD')) IF COND(&OPTION = '3') THEN(CHGVAR VAR(&COMMANDE) VALUE('DSPPFM')) CHGVAR VAR(&COMMANDE) VALUE(&COMMANDE *BCAT &FICHIER) |
QCMDEXC fait précéder l'exécution par l'apparition de l'invite si la commande contient des caractères d'invite sélective ( ? ) Il existe un autre pgm système QCMDCHK |
UNE DATA AREA EST UN OBJET UTILISE POUR TRANSMETTRE DES DONNEES
IL EXISTE 2 TYPES DE DATA AREA ------------------------------ 1 LOCAL DATA AREA (LDA) ----------------------- ELLE EST CREE AUTOMATIQUEMENT PAR LE SYSTEME POUR CHAQUE JOB, =====> ELLE PERMET SEULEMENT LA COMMUNICATION ENTRE PROGRAMMES D'UN JOB |
REGARDONS LA SOLUTION AVEC LA *LDA PROGRAMME DE LANCEMENT PGM DCL VAR(&DEPART) TYPE(*CHAR) LEN(6) DCLF FILE(HEURE) RCDFMT(*ALL) SNDRCVF RCDFMT(HEURF1) IF COND(&IN03) THEN(GOTO CMDLBL(FINCLP)) CHGVAR VAR(&DEPART) VALUE(&HH *CAT &MM *CAT &SS) CHGDTAARA DTAARA(*LDA (1 6)) VALUE(&DEPART) SBMJOB JOB(TRAVSOIR) CMD(CALL SOIR) FINCLP: ENDPGM |
PROGRAMME SOIR. PGM DCL VAR(&DEPART) TYPE(*CHAR) LEN(6) RTVDTAARA DTAARA(*LDA (1 6)) RTNVAR(&DEPART) DLYJOB RSMTIME(&DEPART) ------ ----------------------------- ------ ----------------------------- ------ ----------------------------- ------ ----------------------------- ------ ----------------------------- ------ ----------------------------- ------ ----------------------------- ------ ----------------------------- ------ ----------------------------- ENDPGM |
2 DATAAREA CREE PAR LE PROGRAMMEUR ---------------------------------- CES DATAAREA SONT CREES AVANT D'ETRE UTILISEES |
- EXEMPLE D'UTILISATION DE CETTE DTAAREA |
PROGRAMME DE LANCEMENT PGM DCLF FILE(HEURE) RCDFMT(*ALL) DCL &DEPART *CHAR 6 SNDRCVF RCDFMT(HEURF1) IF COND(&IN03) THEN(GOTO CMDLBL(FINCLP)) CHGVAR VAR(&DEPART) VALUE(&HH *CAT &MM *CAT &SS) CHGDTAARA DTAARA(SOIR) VALUE(&DEPART) SBMJOB JOB(TRAVSOIR) CMD(CALL SOIR) FINCLP: ENDPGM |
PROGRAMME SOIR PGM DCL &SOIR *CHAR 6 RTVDTAARA DTAARA(SOIR) RTNVAR(&SOIR) DLYJOB RSMTIME(&SOIR) ------ ----------------------------- ------ ----------------------------- ------ ----------------------------- ------ ----------------------------- ------ ----------------------------- ------ ----------------------------- ------ ----------------------------- ------ ----------------------------- ENDPGM |
Une autre façon de faire dialoguer les programmes entre eux est d'utiliser les DTAQ. il s'agit d'objets ressemblant à des data area à ceci près : + les entrées peuvent êtres multiples. + les entrées sont classées entre elles FIFO (par défaut) + chaque lecture de DTAQ provoque la suppression de l'entrée lue. + il est possible d'être en attente d'informations sur une DTAQ (temps d'attente paramétrable) + la manipulation se fait par l'intermédiaire de pgms systèmes |
|
EXEMPLE : |