Pause-Café Volubis

pause-café

rendez-vous technique
Pause-Café est une réunion technique
destinée aux informaticiens sur plateforme IBM i.
Elle a lieu 3 à 4 fois par an : en Bretagne et sur internet.

Pause-café #26

Mars 2002

Quelques nouvelles du front :

  • APACHE/TOMCAT disponibles
  • Webfacing
    • fonctionne avec W.A.S 3.5 sur un serveur NT (bons temps de réponses)
    • fonctionne avec TOMCAT (sous webfacing, exportez au format WAR).
  • Iseries Access for the WEB (Client Access pour le WEB)
    • l'accès aux informations 400 fonctionne (assez mauvais temps de réponses)
    • cette partie pourrait tourner sous TOMCAT.
    • Hostpublisher ne fonctionne pas !
    • ne tournerait que sous WAS (et qui plus est, version 3.5).
  • rumeurs de V5R20 en juillet (voir www.volubis.fr) et nouveau processeur REGATA (POWER4)!

Quelques rappels sur les fondamentaux du Web :

l'AS/400 propose maintenant deux serveurs WEB : IBM HTTP server et Apache.

Le but est de fournir au clients (Internet Explorer, Netscape, Opera etc...) des pages HTML statiques ou dynamiques.

Le standard HTML est un langage SGML (comme UIM sur l'AS/400) qui est interprété complétement par la navigateur sur le poste client:

par exemple

voici un texte en <b>GRAS</b> dont une partie est <font color="#FF0000">
rouge</font><br>(suivi d'un passage &agrave; la ligne)

s'affiche :

voici un texte en GRAS dont une partie est rouge
(suivi d'un passage à la ligne)



Très vite il a fallut insérer dans ces pages HTML des données entreprise (commandes en attente, stock disponible etc...).
Pour cela, la norme initiale fut CGI, qui permet l'appel d'un programme sur le serveur, chargé de générer du HTML en réponse. La technique est assez rugueuse mais cela fonctionne (sur l'AS/400 avec des programmes C ou RPG4).

Pour Utiliser CGI en RPG, vous disposez des API suivantes (GAP4 Uniquement)

  • QtmhGetEnv lire le contenu d'une variable d'environnement
  • QtmhRdStin             lire STDIN (le flot en entré)
  • QtmhCvtDb découper STDIN suivant le format d'un fichier BD
  • QtmhWrStout écrire dans STDOUT (le flot en sortie)
    vous devez gnérer un flot commencant par :
    - "content-type : text/html", suivi par du flot HTMLà afficher.
    - "location : http://uuuuuuu", uuuuu étant l'adresse du fichier à afficher (l'url)

 

Pour alléger l'écriture de pgm CGI, la plupart des plates-formes proposent des langages de script ou l'on mélange dans un fichier texte, du HTML, du code (propriétaire) et des ordres d'accès à la base.Il s'agit TOUJOURS de langages interprétés.


L'interpréteur est un pgm CGI déjà écrit traitant ces fichiers, en fournissant au navigateur la page HTML après avoir remplacé les ordres d'accès aux données par les données elle même.

 

Cela s'appelle PHP dans le monde linux (souvent associé à la base MYSQL), ASP pour Microsoft (avec IIS) et Net.Data avec les bases DB2 chez IBM.

Net.Data est basé sur la notion de section, une section représentant soit un page HTML
(un fichier NetData contenant donc plusieurs pages) ou une fonction à exécuter (SQL principalement)

Exemple :

%{================================================================%}
%{=                MACRO NET.DATA                                =%}
%{=                                                              =%}
%{= affichage d'une liste sans sélection (sans page d'appel)     =%}
%{=                                                              =%}
%{= But général : afficher la liste des appellations    (BDVIN1) =%}
%{================================================================%}             
%{****************************************************************%}
%{* SQL1: génère la liste des appellations dans un  tableau HTML *%}
%{****************************************************************%}
%function (DTW_SQL) Fsql1() {
   %{* Requête SQL *%}
   %{*--------------*%}
      select Appellation, Region_code from BDVIN1.Appellations
             order by Appellation
             fetch first 50 rows only
   %{* traitement du résultat *%}
   %{*------------------------*%}
   %report{
     <table border ="1"> 
     <tr> 
     <th><b>Appellation</th>
     <th>Region_code</th>
     </tr>
     {* pour chaque ligne retournée *%}
     %{*-----------------------------*%} 
          %row{
               <tr>
               <td>$(V1)</td>
               <td>$(V2)</td>
               </tr>
          %} 
    </table>
    %}
%}
%{****************************************************************%}
%{*   PAGE1: page HTML liste des appellations (utilise SQL1)     *%}
%{****************************************************************%}
%html (page1) {
  <html>
   <body>
     <p align="center">
     <font size="5" face = "Arial"><b>LISTE des APPELLATIONS<br></b></font>
     </p>
        @Fsql1()
     <BR>
   </body>
 </html>
%}

Affiche la liste des 50 premieres appellations vinicoles, trièes par nom.

  • page1 est la page HTML à afficher, (@Fsql1 sera remplacé par le résultat produit par la fonction).
  • Fsql1 est la fonction SQL, lancant l'ordre Select et mettant en page le résultat.

 

Pour terminer, l'état de l'art est aujourd'hui de travailler dans une architecture N tiers, c'est à dire en découplant le serveur de traitement (les pgm souvent placés avec le serveur WEB) des données (pouvant être situées sur un serveur éloigné).

Cette technique est implémentée avec les serveurs d'application ou serveurs de servlet.

 

Il s'agit d'écrire des programmes JAVA s'exécutant sur le serveur et non sur le poste client , le serveur d'application assurant le lien entre le serveur WEB et la JVM (machine virtuelle java).Ces programmes java pouvant être des classes autonomes (servlet) générant du HTML.


ou contenus dans des pages JSP : pages HTML faisant références à des objets externes [des beans].

Les pages JSP permettant d'intégrer du HTML (conçu par un graphiste) et du code JAVA (écrit par un développeur) dans un même fichier, ce mélange étant reconnu par les principaux éditeurs : Dreamweaver de Macromédia, IBM Websphere Studio, etc ....).

Si, depuis ces pages, vous souhaitez accèder aux données, vous utiliserez JDBC, qui est à Java ce que ODBC st à Windows.

Une autre norme vient compléter tout cela : EJB pour Entreprise Java Bean. Il s'agit d'objets métiers pouvant être situés sur des serveurs externes.D'ailleurs, il est possible de rechercher ces objets dans un annuaire LDAP et de concatcter le serveur proposant le service, au moment du besoin.(architecture distribuée : CORBA).

Ces EJB peuvent être des beans de session , l'objet est instancié au monent où votre code en a besoin et est spécifique à votre code, ou bien persistant (un peu comme un base de données) et accessible à tous. On parle alors de bean d'entité réputés plus lourds (en performmances).

Le support des EJB est un des grandes différences entre en serveur d'application comme TOMCAT (qui ne les supporte pas aujourd'hui) et Websphere Application Serveur (W.A.S).

Tous ces normes sont regroupées dans une plateforme générique ; J2EE.


TOMCAT (c'est le moteur de servlet d'Apache, plus légers que W.A.S)

le moteur de servlet peut s'éxécuter sous forme "inprocess" ou intégré au serveur Apache (on utilise alors JNI ou Java Native Interface) ou bien "outprocess", vous trouverez alors d'un job à part (dans QSSYWRK) dialoguant avec votre serveur web (sur une autre machine ?) via sockets IP.

regardons comment configurer un serveur "inprocess" (en utilisant toujours la configuration sur le port 2001)

choisissez ensuite

le plus simple, la première fois, est de suivre l'assistant (wizard) :

On vous indique que si des fichiers existent déja, il seront reconfigurés.
(à utiliser uniquement la première fois donc)

ici, vous devez choisir

la configuration de servlets ou de pages JSP autonomes
(que vous devrez placer dans les bons répertoires "à la main")

l'utilisation de fichiers archives ou .war (c'est la même chose que les archives java .jar)

Point suivant, servlets (classes java) ou pages JSP (pages "html" utilisant des classes externes)

le magicien à configuré pour vous un répertoire webapps/app1, qui sera automatiquement considéré comme un alias par le serveur web (directive JKmount ... inprocess, dans httpd.conf) contenant deux sous répertoires:

  1. jsp pour vos pages html et vos pages JSP
  2. WEB-INF /classes pour vos fichier .class( java)
  3. vous pourrez placer dans WEB-INF vos fichiers web.xml de définition de servlets

ici, nous testons une page jsp

 


Aller à la Fin

 A P I :
                        

 sous ce terme générique, se cachent des routines systèmes permettant   un accès sûr à des couches basses du système d'exploitation.

 •Il existe des API pour réaliser une action :
   + QCMDEXC[passer une commande], QUSCMDLN[fenêtre avec ligne de commande]

 •Des API de retour d'information :
   + je connais le nom de l'élément et je veux avoir plus de détails.

 •Des API de liste :
   + donnez moi la liste des utilisateurs en session, la liste des membres       d'un fichier, des zones d'un fichier, des spools, etc...

premier exemple:  API QLICOBJD permet de modifier certaines infos d'un objet.


 paramčtres :       - CHAR(10) bibliothčque en retour.


                    - CHAR(20) objet ŕ modifier
                               <--objet(10c)-><--biblio(10c)-->
                                  un nom         un nom ou *LIBL,*CURLIB.


                    - CHAR(10) type d'objet


                    - CHAR(??) infos ŕ modifier, découpé comme suit.


                               BIN(4) nombre d'infos ŕ modifier.


                               puis x fois
                                    BIN(4) clé (détermine l'info ŕ modifier)
                                    BIN(4)     lg de la nouvelle valeur
                                    CHAR(??)   nouvelle valeur.


                    - CHAR(??) code erreur.

                        


Les différentes clés admises:


  !    Clé  ! lg     !   valeur
  ----------------------------------------------------------------------
  !   1     !  30    ! Fichier source <--fich(10c)-><-bib(10c)-><-mbr(10c)->
  !         !        !
  !   2     !  13    ! date de modif du source (format C YY MM DD HH MM SS)
  !         !        !
  !   3     !  13    ! compilateur <-nom-du-produit(7c)-><-version(VxRyMz)->
  !         !        !                (5722xx1)
  !   4     !   8    ! niveau de contrôle
  !         !        !
  !   5     !  13    ! programme sous licence (idem compilateur)
  !         !        !
  !   6     !   7    ! PTF (format XXzzzzz XX = préfixe zzzzz = n° ptf)
  !         !        !
  !   7     !   6    ! APAR (n° d'analyse des incidents sur ce pgm /Azzzzz)
  !         !        !
  !   8     !   1    ! cet objet peut-il ętre modifié par cette API 0=non
  !         !        !                                              1=oui
  !         !        !
  !   9     !  10    ! attribut défini par l'utilisateur.
  !         !        !
  !  10     !  50    ! texte decriptif.
  !         !        !
  !  11     !   1    ! remise ŕ zéro du compteur nb de jours d'utilisation
  !         !        !  0=non , 1=oui.
  !         !        !
  !  12     !   4    ! ID langage associé ŕ ce produit (29xx)
  !         !        !
  !  13     !   4    ! option d'un logiciel sous licence  0=*BASE, 01 ŕ 99
  !         !        !
  !  14     !   4    ! ID composant (laissé ŕ votre imagination)
  ----------------------------------------------------------------------


                        

 exemple de CL renommant le source d'un objet et mettant ŕ jour l'objet


 /* RNMOBJSRC  */
             
             RNMM       FILE(&SRCL/&SRCF) MBR(&SRCM) +
                          NEWMBR(&NEWNAME)
 /* API QUI PERMET DE MODIFIER LES INFOS DANS L'OBJET        */


             CHGVAR %BIN(&CHGINFO 1 4)  1 /* NBR DE MODIFS        */
             CHGVAR %BIN(&CHGINFO 5 4)  1 /* CLE 1 = MODIF SOURCE */
             CHGVAR %BIN(&CHGINFO 9 4) 30 /* LG MODIF             */
             CHGVAR %SST(&CHGINFO 13 30) +
                                        (&SRCF *CAT &SRCL *CAT &NEWNAME)
             CHGVAR %BIN(&ERRCOD)       0
             CALL QLICOBJD PARM( +
                                 &RTNLIB    +
                                 &NOMOBJ    +
                                 &OBJTYP    +
                                 &CHGINFO   +
                                 &ERRCOD    )
                        

 CPP de la commande CHGOBJAPI

   ce pgm permet de modifier certains attributs à priori inacessibles d'un objet:

   + coordonnées source , date de modif du source
   + produit (au sens logiciel sous licence) ayant créé cet objet
   + attribut utilisateur (10 c à votre disposition)
   + objet modifiable par API ? (celle-ci entre autre)
1/     Calcul le nombre d'infos ŕ modifier (&NBR) 2/     Concatčne les différentes modifs dans une seule variable       sous la forme <-clé-><-lg-><-nouvelles valeurs->  repété x fois
             PGM        PARM(&OBJQ &OBJT &SRCELEM &SRCDATE +
                          &COMPILELEM &PRDELEM &OPTION &ATTRIB +
                          &COMPOS &ALWCHG)

             DCL        VAR(&OBJQ) TYPE(*CHAR) LEN(20)              DCL        VAR(&OBJT) TYPE(*CHAR) LEN(10)              DCL        VAR(&SRCELEM) TYPE(*CHAR) LEN(32)              DCL        VAR(&SRCDATE) TYPE(*CHAR) LEN(13)              DCL        VAR(&COMPILELEM) TYPE(*CHAR) LEN(15)              DCL        VAR(&PRDELEM) TYPE(*CHAR) LEN(15)
             DCL        VAR(&OPTION) TYPE(*CHAR) LEN(2)
             DCL        VAR(&ATTRIB) TYPE(*CHAR) LEN(10)
             DCL        VAR(&COMPOS) TYPE(*CHAR) LEN(10)
             DCL        VAR(&ALWCHG) TYPE(*CHAR) LEN(1)

             DCL        VAR(&RTNLIB) TYPE(*CHAR) LEN(10)              DCL        VAR(&CODERR) TYPE(*CHAR) LEN(4) +                           VALUE(X'00000000')              DCL        VAR(&NBR) TYPE(*DEC) LEN(2 0)              DCL        VAR(&VAR2000) TYPE(*CHAR) LEN(2000)              DCL        VAR(&X41) TYPE(*CHAR) LEN(1) VALUE(X'41')              DCL        VAR(&DEP) TYPE(*DEC) LEN(4 0) VALUE(5)  /* VARIABLES UTILISEES PAR LA GESTION DE MESSGAES */              DCL        &ERRORSW *LGL                     /* SWITCH  */              DCL        &MSGID *CHAR LEN(7)               /* ID MSG  */              DCL        &MSGDTA *CHAR LEN(100)            /* DATA    */              DCL        &MSGF *CHAR LEN(10)               /* FICHIER */              DCL        &MSGFLIB *CHAR LEN(10)            /* BIBLI   */
             MONMSG     MSGID(CPF0000) EXEC(GOTO ERREUR)
 /* CORPS DU PROGRAMME */

/* SOURCE*/ IF (%BIN(&SRCELEM 1 2) > 1) DO                IF (%SST(&SRCELEM 3 5) ^= '*SAME')  THEN(DO)                CHGVAR &NBR (&NBR + 1)                CHGVAR %BIN(&VAR2000 &DEP 4) 1  /* CLE 1 */                CHGVAR &DEP (&DEP + 4)                CHGVAR %BIN(&VAR2000 &DEP 4) 30  /* LG INFOS */                CHGVAR &DEP (&DEP + 4)                CHGVAR %SST(&VAR2000 &DEP 30) %SST(&SRCELEM 3 30)                CHGVAR &DEP (&DEP + 30)                ENDDO              ENDDO
/* DATE */   IF (&SRCDATE ^= '*SAME') THEN(DO)                CHGVAR &NBR (&NBR + 1)                CHGVAR %BIN(&VAR2000 &DEP 4) 2  /* CLE 2 */                CHGVAR &DEP (&DEP + 4)                CHGVAR %BIN(&VAR2000 &DEP 4) 13  /* LG INFOS */                CHGVAR &DEP (&DEP + 4)                CHGVAR %SST(&VAR2000 &DEP 13) &SRCDATE                CHGVAR &DEP (&DEP + 13)              ENDDO

/* COMPIL*/ IF (%BIN(&COMPILELEM 1 2) > 0) DO                IF (%SST(&COMPILELEM 3 5) ^= '*SAME')  THEN(DO)                CHGVAR &NBR (&NBR + 1)                CHGVAR %BIN(&VAR2000 &DEP 4) 3   /* CLE 3 */                CHGVAR &DEP (&DEP + 4)                CHGVAR %BIN(&VAR2000 &DEP 4) 13   /* LG INFOS */                CHGVAR &DEP (&DEP + 4)                IF (%SST(&COMPILELEM 3 5) = '*BLANK')    +                CHGVAR %SST(&VAR2000 &DEP 13) '             '                ELSE +                CHGVAR %SST(&VAR2000 &DEP 13) %SST(&COMPILELEM 3 13)                CHGVAR &DEP (&DEP + 13)                ENDDO              ENDDO
/* PROD  */ IF (%BIN(&PRDELEM 1 2) > 0) DO                IF (%SST(&PRDELEM 3 5) ^= '*SAME')  THEN(DO)                CHGVAR &NBR (&NBR + 1)                CHGVAR %BIN(&VAR2000 &DEP 4) 5   /* CLE 5 */                CHGVAR &DEP (&DEP + 4)                CHGVAR %BIN(&VAR2000 &DEP 4) 13   /* LG INFOS */
               CHGVAR &DEP (&DEP + 4)
               IF (%SST(&PRDELEM 3 5) = '*BLANK')    +
               CHGVAR %SST(&VAR2000 &DEP 13) '             '
               ELSE +
               CHGVAR %SST(&VAR2000 &DEP 13) %SST(&PRDELEM 3 13)
               CHGVAR &DEP (&DEP + 13)
               ENDDO
             ENDDO

/* OPTION*/ IF (%SST(&OPTION 1 5) ^= '*SAME') DO                CHGVAR &NBR (&NBR + 1)                CHGVAR %BIN(&VAR2000 &DEP 4) 13  /* CLE 13 */                CHGVAR &DEP (&DEP + 4)                CHGVAR %BIN(&VAR2000 &DEP 4) 2    /* LG INFOS */                CHGVAR &DEP (&DEP + 4)                CHGVAR %SST(&VAR2000 &DEP 2) &OPTION                CHGVAR &DEP (&DEP + 2)              ENDDO
/* ATTRIB*/ IF (%SST(&ATTRIB 1 5) ^= '*SAME') DO                CHGVAR &NBR (&NBR + 1)                CHGVAR %BIN(&VAR2000 &DEP 4) 9  /* CLE 9 */
               CHGVAR &DEP (&DEP + 4)
               CHGVAR %BIN(&VAR2000 &DEP 4) 10   /* LG INFOS */
               CHGVAR &DEP (&DEP + 4)
               CHGVAR %SST(&VAR2000 &DEP 10) &ATTRIB
               CHGVAR &DEP (&DEP + 10)
             ENDDO

/* COMPOS*/ IF (%SST(&COMPOS 1 5) ^= '*SAME') DO                CHGVAR &NBR (&NBR + 1)                CHGVAR %BIN(&VAR2000 &DEP 4) 14  /* CLE 14 */                CHGVAR &DEP (&DEP + 4)                CHGVAR %BIN(&VAR2000 &DEP 4) 4   /* LG INFOS */                CHGVAR &DEP (&DEP + 4)                CHGVAR %SST(&VAR2000 &DEP 4) &COMPOS                CHGVAR &DEP (&DEP + 4)              ENDDO
/* MODIF */ IF (&ALWCHG ^= '2') DO                CHGVAR &NBR (&NBR + 1)                CHGVAR %BIN(&VAR2000 &DEP 4) 8  /* CLE 8 */                CHGVAR &DEP (&DEP + 4)                CHGVAR %BIN(&VAR2000 &DEP 4) 1   /* LG INFOS */
               CHGVAR &DEP (&DEP + 4)
               CHGVAR %SST(&VAR2000 &DEP 1) &ALWCHG
             ENDDO

             CHGVAR     VAR(%BIN(&VAR2000 1 4)) VALUE(&NBR)
             CALL QLICOBJD PARM(      +                            &RTNLIB    +                            &OBJQ      +                            &OBJT      +                            &VAR2000   +                            &CODERR)
 /* RENVOI DES MESSAGES DE TYPE *COMP SI FIN NORMALE */
 COMPMSG:    RCVMSG     MSGTYPE(*COMP) MSGDTA(&MSGDTA) MSGID(&MSGID) +                           MSGF(&MSGF) SNDMSGFLIB(&MSGFLIB)              IF         (&MSGID *EQ '       ') RETURN  /* FIN DU PGM */              SNDPGMMSG  MSGID(&MSGID) MSGF(&MSGFLIB/&MSGF) +                           MSGDTA(&MSGDTA) MSGTYPE(*COMP)              GOTO       COMPMSG /* BOUCLE SUR MESSAGES *COMP      */
              /*----------------------------------------*/
 ERREUR:      /*        GESTION DES ERREURS             */
              /*----------------------------------------*/
             IF         &ERRORSW SNDPGMMSG MSGID(CPF9899) +
                          MSGF(QCPFMSG) MSGTYPE(*ESCAPE) /* 2EME FOIS*/
                                                         /* ARRET PGM*/
             CHGVAR     &ERRORSW '1' /* MISE EN PLACE DU SWTICH     */

 /* RENVOI DES MESSAGES DE TYPE *DIAG SI FIN ANORMALE */  DIAGMSG:    RCVMSG     MSGTYPE(*DIAG) MSGDTA(&MSGDTA) MSGID(&MSGID) +                           MSGF(&MSGF) SNDMSGFLIB(&MSGFLIB)              IF         (&MSGID *EQ '       ') GOTO EXCPMSG              SNDPGMMSG  MSGID(&MSGID) MSGF(&MSGFLIB/&MSGF) +                           MSGDTA(&MSGDTA) MSGTYPE(*DIAG)              GOTO       DIAGMSG /* BOUCLE SUR MESSAGES *DIAG      */
 /* RENVOI DU MESSAGE D'ERREUR                        */  EXCPMSG:    RCVMSG     MSGTYPE(*EXCP) MSGDTA(&MSGDTA) MSGID(&MSGID) +                           MSGF(&MSGF) SNDMSGFLIB(&MSGFLIB)              SNDPGMMSG  MSGID(&MSGID) MSGF(&MSGFLIB/&MSGF) +                           MSGDTA(&MSGDTA) MSGTYPE(*ESCAPE)              ENDPGM

 deuxième exemple : QMHRTVM, retourne les caractèristiques d'un message
  dans un *MSGF. la clé du message doit être fournie.
                 le paramètre OPTION permet de demander le message suivant.

      * variable retour pour le format RTVM0300      Dmessage_rt       DS         32767      D  byte_retour                  10I 0      D  byte_dispo                   10I 0      D  msgid_rt                      7    overlay(message_rt : 27)      D  msg_offset                   10I 0 overlay(message_rt : 65)      D  msg_retour                   10I 0 overlay(message_rt : *next)      D  msg_dispo                    10I 0 overlay(message_rt : *next)      D  msg2_offset                  10I 0 overlay(message_rt : 77)      D  msg2_retour                  10I 0 overlay(message_rt : *next)      D  msg2_dispo                   10I 0 overlay(message_rt : *next)      D  data                       9999
     d msg1            S            256      d msg2            S           9000

      * divers paramètres      Dmessage_rt_lg    S             10I 0 inz(%size(message_rt))      Dformat           S              8    inz('RTVM0300')      dmsgid            S              7      dmsgf             S      dmsgdta           S              1      dmsgdta_lg        S             10I 0 inz(0)      dremplace_var     S             10    inz('*NO')      dremplace_spc     S             10    inz('*NO')
     Derror_code       DS      D  err_lg                       10I 0 inz(%size(error_code))      D  err_retour                   10I 0      D  err_filler                    1      D  err_msgid                     7
     Doption           S             10    inz('*FIRST')      Dmsg_ccsid        S             10I 0 inz(0)      Ddta_ccsid        S             10I 0 inz(0)
      * prototype d'appel à l'API
     Drtvmsg           PR                  EXTPGM('QMHRTVM')
     D                             9999
     D                               10I 0
     D                                8
     d                                7
     d                               20
     d                                1
     d                               10I 0
     d                               10
     d                               10
     D                               16
     D                               10
     D                               10I 0
     D                               10I 0
      * on recoit msgf et bibliothèque en paramètre
     C     *entry        plist
     C                   parm                    p_msgf           10
     C                   parm                    p_msgfl          10
      /free
       msgf = p_msgf + p_msgfl;
       exsr lecture;
       option = '*NEXT';
       dow byte_dispo > 0;

         msg1 = %subst(message_rt : msg_offset + 1 : msg_retour);
         if msg2_offset > 0;             msg2 = %subst(message_rt : msg2_offset + 1 : msg2_retour);          else;             msg2 = *blanks;          endif;
         msgid = msgid_rt;  // positionnement sur le message suivant          exsr lecture;        enddo;        *inlr = *on;
        //   appel à l'API.        begsr lecture;         rtvmsg(message_rt : message_rt_lg : format : msgid : msgf : msgdta :                 msgdta_lg  : remplace_var : remplace_spc : error_code :                 option     : msg_ccsid    : dta_ccsid);        endsr;       /end-free

 Troisième cas,les API produisant une liste dans un USER SPACE.

        Structure d'un USER SPACE.
 De                   à                   ..........................           --       1       01: Espace utilisateur     :            ! Octets à blanc pour                 : (64 octets à blanc)    :            ! la communication                 ..........................64         -- entre programmes       2       65: ENTETE GENERALE        :            !                 :   DU USER SPACE        :             > Découpage image                 :                        :            !   suivante                 ..........................140        --       3      141: Rappel des paramètres  :  INPUT     !                 :  reçus par l'API       :            !                 ..........................            !       4         : En-tête API            :  HEADER    !  voir structures                 :  (valeurs rencontrées) :             > dans QSYSINC                 ..........................            !  (5769ss1 opt 13.)       5         : Liste générée par API  :  LIST      !                 :  (liste des membres,   :           --                 :         des objets...) :                 :........................:???

 .......................................................................
 :  De   :   à   :Fmt: Signification ( DECOUPAGE DE "ENTETE" )         :
 ......................................................................:
 :  65   :  68   : B : Taille de l'en-tête générale (2)                :
 :  69   :  72   : C : Version                                         :
 :  73   :  80   : C : Nom du format utilisé par l'API (ex:OBJD0100)   :
 :  81   :  90   : C : Nom de l'API ayant généré la liste              :
 :  91   : 103   : C : Siècle-date-heure(SDDDDDDHHHHHH) de remplissage :
 : 104   : 104   : C : Etat (C=Complet,I=Incomplet,P=Partiel)          :
 : 105   : 108   : B : Nb d'octets utilisés dans le user space         :
 :       :       :                                                     :
 : 109   : 112   : B : Déplacement pour atteindre la zone INPUT        :
 : 113   : 116   : B : Taille de la zone INPUT                         :
 :       :       :                                                     :
 : 117   : 120   : B : Déplacement pour atteindre la zone HEADER       :
 : 121   : 124   : B : Taille de la zone HEADER                        :
 :       :       :                                                     :
 : 125   : 128   : B : Déplacement pour atteindre la liste (LIST)      :
 : 129   : 132   : B : Taille de la liste                              :
 : 133   : 136   : B : Nb d'entrées dans la liste                      :
 : 137   : 140   : B : Taille de chaque entrée.                        :
.:.......:.......:...:.................................................:

      *
      *  Avec RPGIV en 3.70, la gestion des pointeurs pour lire un *USRSPC
      *   est simplifiée, puisqu'il est possible d'écrire :
      *
      *      C                   eval      pt = pt + lgposte
      *
      *   pt étant le pointeur , "lgposte" la variable en entête de User
      *     Space, donnant la longueur d'un poste (137/140)
      *
      * lecture d'un user space contenant la liste des membres d'un fichier
      * ===================================================================

      * va contenir l'adresse de début du User Space      Dpointeur         s               *       * l'entête (positions 125 à 140)       *      Dptrinfos         s               *      DRTVINF           ds                  based(ptrinfos)      D  offset                       10i 0      D  taille                       10i 0      D  nbpostes                     10i 0      D  lgposte                      10i 0

      * la liste des membres       *      dptrliste         s               *      DLIST             ds                  based(ptrliste)      d  ... (informations membre: nom, date de création etc...)

      * prototype pour API qui retrouve pointeur de début      dQUSPTRUS         PR                  EXTPGM('QUSPTRUS')      d  space                        20    const      d  ptr                            *       /free
       // extraction du pointeur de début (le user space doit exister)          QUSPTRUS('EXEMPLE   QTEMP' : pointeur);
       // positionnement sur la partie entête           ptrinfos = pointeur + 124            ;

       // maintenant RTVINF  (DS) a un contenu valide
       //  (rappel)
       //RTVINF   e       ds                  based(ptrinfos)
       //  offset                       10i 0
       //  taille                       10i 0
       //  nbpostes                     10i 0
       //  lgposte                      10i 0


       // positionnement sur le premier poste        //  (la structure "LIST" vient se positionner "par dessus")
          ptrliste = pointeur + offset  ;

       // boucle (nbpostes fois)           for       i = 1 to nbpostes   ;        // traitement d'un élément              ...              ...              ...              if        i < nbpostes ;                 ptrliste = ptrliste + lgposte;              endif ;           endfor ;
      /end-free
 Voilà, tout ceci est assez classique (au moins assez ancien [V2Rxx] ),   si ce n'est l'utilisation des pointeurs et le format libre du GAP4.

 Il reste une série d'API que nous n'avons pas du tout l'habitude d'utiliser   ce sont les routines destinées au langage C.
 Le C est un langage plutot pauvre, puissant et livré avec une bibliothèque d'outils   assez étoffée. Ces routines sont externes et doivent être "linkées"   au pgm principal [main()].
 Sur AS/400, elles sont fournies sous la forme de programmes de service   dans la cadre des techniques ILE. C'est a dire utilisables AUSSI en CLLE   [ILE CL] ou en RPGLE [ILE GAP4].
Par exemple, utilisation des fonctions mathémathiques (source news/400):
*  =========================================================
*  =  Using C function library trigonometric functions     =
* =========================================================
 H BndDir( 'QC2LE' )
   H DftActGrp( *No )
D GetCosine       Pr             8F   ExtProc( 'cos' )
D                                8F   Value
D GetArcCosine    Pr             8F   ExtProc( 'acos' )
D                                8F   Value
D                 Pi             8F
D Angle           S              3 0    Inz( 30 )
D Radians         S              8F
D Cosine          S              8F
C                   Eval   Pi = GetArcCosine( -1 )
C                   Eval       Radians = ( Angle * Pi ) / 180
C                   Eval   Cosine = GetCosine( Radians )
C                   Eval   *InLR = *On
dans ces programmes de service , vous trouverez tout ce qui permet de manipuler
des fichiers streams (dans IFS).
 Démonstration, avec l'API stat() qui permet d'obtenir des informations générales
 sur un fichier stream, s'il existe, donc aussi, de tester l'existence.
 ce pgm CL (type de source CLLE) vérifie l'exitence d'un fichier IFS.
             PGM        PARM(&PARM)
             DCL        VAR(&PARM) TYPE(*CHAR) LEN(256)              DCL        VAR(&RTNVALINT) TYPE(*CHAR) LEN(4)              DCL        VAR(&RTNVAL) TYPE(*CHAR) LEN(2)              DCL        VAR(&PATH) TYPE(*CHAR) LEN(100)              DCL        VAR(&NULL) TYPE(*CHAR) LEN(1) VALUE(X'00')              DCL        VAR(&BUF) TYPE(*CHAR) LEN(4096)
             CHGVAR     VAR(&PATH) VALUE(&PARM *TCAT &NULL)
             CALLPRC    PRC('stat') PARM(&PATH &BUF) +                           RTNVAL(%BIN(&RTNVALINT 1 4))
             CHGVAR     VAR(&RTNVAL) VALUE(%BIN(&RTNVALINT))
             IF         COND(&RTNVAL *NE '00') THEN(SNDPGMMSG +                           MSGID(CPF9897) MSGF(QCPFMSG) +                           MSGDTA('Fichier ' !! &PARM !< ' non +                           trouvé.') MSGTYPE(*ESCAPE))              ENDPGM
 même routine, mais utilisée en RPG (il s'agit ici de retrouver la taille)

      * NOTE: Compiler avec DFTACTGRP(*NO) DFTACTGRP(QILE) BDNDIR('QC2LE')       *       * IFS API prototypes       *       * stat()       *      Dstat             PR            10I 0 extproc('stat')      Dpathptr                          *   value      Dstatptr                          *   value       *       * variables de travail       *
     D statds          DS
     D  mode                         10U 0
     D  ino                          10U 0
     D  nlink                         5U 0
     D  filler1                       5U 0
     D  uid                          10U 0
     D  gid                          10U 0
     D  size                         10U 0
     D  filler2                     256

     DFile_exists      S             10I 0      Dpathptr          S               *      Dpathname         S            256      Dstatptr          S               *       *       * Main()       *      C     *entry        plist      C                   parm                    filename        255      C                   parm                    taille           10 0       /free
        //attribution d'un pointeur sur la variable nom du chemin
           pathname = %trim(filename)+x'00' ;
           pathptr = %addr(pathname)        ;
           statptr = %addr(statds)          ;
        // Appel de l'API IFS
            File_Exists = stat(pathptr:statptr) ;

            if        File_Exists = 0 ;                       taille = size   ;             endif  ;         // fin du pgm.             *inlr = *on ;       /end-free

et enfin, utilisation des routines open(), read(), write() etc...
 le pgm qui suit est un extrait de l'exellent redbook : SG24-5402-00 
    Who Knew You Could Do That with RPG IV?     A Sorcerers Guide to System Access and More  [ www.redbooks.ibm.com ]

 *****************************************************************       * RPG PROGRAM EXAMPLE       * This program is an example of using AS/400 Unix-style APIs       * in an ILE-RPG program.       *       * LICENSE AND DISCLAIMER       * ----------------------       * This material contains IBM copyrighted sample programming       * source code.  IBM grants you a nonexclusive license to use,       * execute, display, reproduce, distribute and prepare derivative       * works of this sample code.  The sample code has not been       * thoroughly tested under all conditions.  IBM, therefore, does       * not warrant or guarantee its reliability, serviceablity, or       * function.  All sample code contained herein is provided to you       * "AS IS." ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT       * NOT LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILLITY AND       * FITNESS FOR A PARTICULAR PURPOSE ARE HEREBY DISCLAIMED.       *       * COPYRIGHT       * ---------       *  (C) COPYRIGHT IBM CORP. 1997, 1998
      *  ALL RIGHTS RESERVED.
      *  US GOVERNMENT USERS RESTRICTED RIGHTS -
      *  USE, DUPLICATION OR DISCLOSURE RESTRICTED
      *  BY GSA ADP SCHEDULE CONTRACT WITH IBM CORP.
      *  LICENSED MATERIAL - PROPERTY OF IBM
      *
      *  COMMENTS/QUESTIONS
      *  ------------------
      *  Please send comments or questions via e-mail to Ray Bills
      *  at rainfall@us.ibm.com also phone calls are welcome to Ray
      *  at 507-253-4699
      *
      *  I would strongly suggest
      *  that you remove all of the function prototypes into their
      *  own RPG include file.  That way, when IBM comes out with the
      *  official version of the RPG include file, your code won't be
      *  impacted that much.
      *
      *  The program reads through a DDS-defined AS/400 Physical File
      *  and creates an ASCII version of it.  There is no attempt
      *  to do any selection criteria, but that could be easily added
      *  in your real versions.  Also, the format of the lines of
      *  output can be easily changed to match the format of whatever
      *  PC or Unix file you desire.
      *
      *  Questions about this code are freely answered by ME
      *
      *
      *  Please Note:  I freely stole large protions of this code from
      *                Massimo Marasco of IBM Italy, so if this turns
      *                out to be successful and usefull, he should
      *                get much of the credit.
      *
      *****************************************************************

      *****************************************************************       *       *  START OF WHAT SHOULD BE IN A RPG INCLUDE FILE       *       *****************************************************************       *****************************************************************       *       * (from member STDIO, file H, library QSYSINC)       *
      * QBFC_EXTERN void perror(const char *);
      *
      *****************************************************************
      *
     Dperror           PR            10I 0 EXTPROC('perror')
      * string to be filled
     D                                 *   VALUE
      *****************************************************************
      *
      * (from member STDIO, file H, library QSYSINC)
      *
      * QBFC_EXTERN int sprintf(const char *, const char *, ...);
      *
      *****************************************************************
      * value returned = 0 (OK), -1 (error)
     Dsprintf          PR            10I 0 EXTPROC('sprintf')
      * string to be filled
     D                                 *   VALUE
      * format string
     D                                 *   VALUE
      *
     D                               10I 0 VALUE OPTIONS(*NOPASS)
      *
     D                                 *   VALUE OPTIONS(*NOPASS)
      *****************************************************************
      *****************************************************************
      *
      * (from member FCNTL, file H, library QSYSINC)
      *
      * QBFC_EXTERN int open(const char *, int, ...);
      *
      *****************************************************************
      * value returned = file descriptor (OK), -1 (error)
     Dopen             PR            10I 0 EXTPROC('open')
      * path to be opened.
     D                                 *   VALUE
      * Open flags
     D                               10I 0 VALUE
      * (OPTIONAL) mode (describes access rights to the file)
     D                               10U 0 VALUE OPTIONS(*NOPASS)
      * (OPTIONAL) codepage (specified for ascii data)
     D                               10U 0 VALUE OPTIONS(*NOPASS)
      *****************************************************************
      *****************************************************************
      *
      * (from member UNISTD, file H, library QSYSINC)
      *
      * QBFC_EXTERN ssize_t read(int,  void *, size_t);
      *
      *****************************************************************
      * value returned = number of bytes actually read, or -1
     Dread             PR            10I 0 EXTPROC('read')
      * file descriptor returned from open()
     D                               10I 0 VALUE
      * data received
     D                                 *   VALUE
      * number of bytes to read
     D                               10U 0 VALUE
      *****************************************************************
      *****************************************************************
      *
      * (from member UNISTD, file H, library QSYSINC)
      *
      * QBFC_EXTERN ssize_t write(int, const void *, size_t);
      *
      * Definition of type ssize_t
      * (from member TYPES, file SYS, library QSYSINC)
      *
      * typedef int           ssize_t;
      *
      * Definition of type size_t
      * (from member TYPES, file SYS, library QSYSINC)
      *
      * typedef unsigned int   size_t;
      *
      *****************************************************************
      * value returned = number of bytes actually written, or -1
     Dwrite            PR            10I 0 EXTPROC('write')
      * file descriptor returned from open()
     D                               10I 0 VALUE
      * data to be written
     D                                 *   VALUE
      * number of bytes to write
     D                               10U 0 VALUE
      *****************************************************************
      *****************************************************************
      *
      * (from member UNISTD, file H, library QSYSINC)
      *
      * QBFC_EXTERN int close(int);
      *
      *****************************************************************
      * value returned = 0 (OK), or -1
     Dclose            PR            10I 0 EXTPROC('close')
      * file descriptor returned from open()
     D                               10I 0 VALUE
      *****************************************************************
      *****************************************************************
      *****************************************************************
      *****************************************************************
      *
      *  END OF WHAT SHOULD BE IN A RPG INCLUDE FILE
      *
      *****************************************************************
      *
      *****************************************************************
      *  RC is used to store the Return Code of the various IFS APIs
      *****************************************************************
     DRC               S             10I 0
      *****************************************************************
      *  FileNam is the name of the file in the IFS namespace.  You
      *  can change this to be whatever you want.  Your life will be
      *  a lot easier if you make sure it starts with a slash '/'.
      *****************************************************************
     DFileNam          S             50A   INZ('/junk.dat')
     DFileNamP         S               *   INZ(%ADDR(FileNam))
      *****************************************************************
      *  FileDescr is the File descriptor that gets assigned by the
      *  open API and gets used for all of the read, write and close AP
      *****************************************************************
     DFileDescr        S             10I 0
      *****************************************************************
      *  The following comments explain how the various numeric fields
      *  were assigned for the open API.  The values mentioned here are
      *  from the FCNTL member of the H file in the QCLE library.
      *****************************************************************
      *  The following are for the 'oflag' parameter:
      *
      *  define O_CREAT     0x0000008   /* Create the file if not there
      *  define O_TRUNC     0x0000040   /* Clear file if it is there
      *  define O_WRONLY    0x0000002   /* Open for writing only
      *  define O_TEXTDATA  0x1000000   /* Translate ebcidic/ascii
      *  define O_CODEPAGE  0x0800000   /* Create file in ascii ccsid
      *
      *****************************************************************
     DO_CREAT          S             10I 0 INZ(8)
     DO_RDWR           S             10I 0 INZ(4)
     DO_TEXTDATA       S             10I 0 INZ(16777216)
     DO_CODEPAGE       S             10I 0 INZ(8388608)
     Doflag            S             10I 0 INZ(0)
      *
      *****************************************************************
      *  The mode parameter for the open API is set to give acces
      *  all users.  0x01B6 = rw-w-w-data rights
      ***********************************************************
     Domode            S             10U 0 INZ(438)
      *
      ***********************************************************
      *  cp is used to set the code page (CCSID) of the IFS file
      *  a common US English ASCII.  Others code be substituted a
      *  desired.
      ***********************************************************
      * ASCII (ccsid 437 = 0x1B5)
     Dcp               S             10U 0 INZ(819)
      *
      ***********************************************************
      *  The following fields are used to help fo the string
      *  formatting and writing...
      *****************************************************************
      *
     DZeroBin          S             50A   INZ(*ALLX'00')
     DNLZero           S              2A   INZ(X'1500')
      *
      *****************************************************************
      *  SI_Fmt is used to hold the format that you want to put in your
      *  ascii file.  This follows the format for the C function called
      *  printf.  So if you are unfamiliar with it, check out a C book
      *  for further details.  The quick tutorial is as follows:
      *  %d  means put a SIGNED number here. (ex. -123 or 456)
      *  ,   the comma is used to delimit the fields
      *  %s  means to put a string or name here.
      *****************************************************************
      *
     DSI_Fmt           S             50A   INZ('%d, %s')
     DSI_FmtP          S               *   INZ(%ADDR(SI_Fmt))
      *
      *****************************************************************
      *  SI_Msg is used to hold the string or name data from the DB fil
      *  I have put the phrase "Hello World" it there just for fun.
      *****************************************************************
      *
     DSI_Msg           S             50A   INZ('Hello World')
     DSI_MsgP          S               *   INZ(%ADDR(SI_Msg))
      *
      *****************************************************************
      *  num is where I will put some numeric data.  Note that the EVAL
      *  statement below will take care of unpacking the data from the
      *  DB file.  The SI_Fmt above takes care of putting the '-' sign
      *  in the right place automatically for us!!
      *****************************************************************
      *
     Dnum_ds           DS
     D num_Hex                        4A   INZ(X'00000000')
     D num                           10I 0 OVERLAY(num_Hex)
      *
      *****************************************************************
      *  Buf is the place where we build our string that will go into t
      *  ascii file for us.  It needs to be big enough to hold all of
      *  the data for one record of output (including formatting).
      *****************************************************************
      *
     DBuf              S            100A
     DBufP             S               *   INZ(%ADDR(Buf))
     DBufLen           S             10U 0 INZ(100)
      *
      *****************************************************************
      *  Here we start the logic.
      *
      *  1. Use the open API to create the file, specifying that the da
      *  to be stored in it will be in codepage (ccsid) 437 (or whateve
      *  you change it to above in the CP field).
      *
      *****************************************************************
      *
     C                   EVAL      FileNam=%TRIM(FileNam) + ZeroBin
     C                   Z-ADD     O_CREAT       oflag
     C                   ADD       O_RDWR        oflag
     C                   ADD       O_CODEPAGE    oflag
     C                   EVAL      FileDescr=open(FileNamP:oflag:omode:cp)
     C                   IF        FileDescr=-1
     C                   EVAL      RC = perror(FileNamP)
     C                   return
     C                   ENDIF
      *****************************************************************
      *
      *  2. Use the close API to close the file.  This may seem strange
      *  since we are going to turn right around and reopen the file,
      *  but that is so it will do the automatic translation for us fro
      *  our current job CCSID (whatever it happens to be) into the
      *  ascii CP.
      *****************************************************************
      *
     C                   EVAL      RC=close(FileDescr)
      *
     C                   IF        RC=-1
     C                   EVAL      RC = perror(FileNamP)
     C                   return
     C                   ENDIF
      *
      *****************************************************************
      *
      *  3. Use the open API to reopen the file with NEW oflag values.
      *  These will handle the ebcidic to ascii translation for us.
      *****************************************************************
     C                   Z-ADD     O_RDWR        oflag
     C                   ADD       O_TEXTDATA    oflag
     C                   EVAL      FileDescr=open(FileNamP:oflag)
      *
     C                   IF        FileDescr=-1
     C                   EVAL      RC = perror(FileNamP)
     C                   return
     C                   ENDIF
      *****************************************************************
      *
      *  4.Use the write API to put translate the data from ebcidi
      *     to ascii and store it in the IFS file.
      *****************************************************************
      *
     C                   EVAL      buf='Hello Ray' + X'15'
     C                   EVAL      RC=write(FileDescr: BufP: BufLen)
     C                   return
     C                   ENDIF

      *
      *****************************************************************
      *
      *  5. Use the close API to close the IFS file.
      *
      *****************************************************************
      *****************************************************************
     C                   EVAL      RC=close(FileDescr)
     C                   IF        RC=-1
     C                   EVAL      RC = perror(FileNamP)
     C                   return
     C                   ENDIF
      *
     C                   SETON                                        Lr

 ce source est assez complet  (peut-être trop car il reprend des déclarations un peu inutiles, à titre d'exemple)
 vous noterez l'ouverture du fichier une première fois pour création.   puis une deuxième fois pour la conversion :le système transforme vos data   en code-page du fichier [ascii], uniquement sur un fichier existant.

Pour terminer un exemple récapitulatif, génération d'un fichier CSV à partir d'un *MSGF :

     H  DFTACTGRP(*no) ACTGRP('QILE') BNDDIR('QC2LE')
     D*****************************************************************
     D* PROTOTYPES IFS
     D*****************************************************************
     D*** open sur IFS
     Dopen             PR            10I 0 EXTPROC('open')
     D  nomfichier                     *   VALUE
     D  openflags                    10I 0 VALUE
     D  mode                         10U 0 VALUE OPTIONS(*NOPASS)
     D  codepage                     10U 0 VALUE OPTIONS(*NOPASS)
     D*** lecture IFS
     Dread             PR            10I 0 EXTPROC('read')
     D  filehandle                   10I 0 VALUE
     D  datareceived                   *   VALUE
     D  nbytes                       10U 0 VALUE
     D*** écriture IFS
     Dwrite            PR            10I 0 EXTPROC('write')
     D  filehandle                   10I 0 VALUE
     D  datatowrite                    *   VALUE
     D  nbytes                       10U 0 VALUE
     D*** fermeture IFS
     Dclose            PR            10I 0 EXTPROC('close')
     D  filehandle                   10I 0 VALUE
     D*****************************************************************
     D* Constantes pour IFS
     D*** File Access Modes for open()
     D O_RDONLY        S             10I 0 INZ(1)
     D O_WRONLY        S             10I 0 INZ(2)
     D O_RDWR          S             10I 0 INZ(4)
     D*** oflag Values for open()
     D O_CREAT         S             10I 0 INZ(8)
     D O_EXCL          S             10I 0 INZ(16)
     D O_TRUNC         S             10I 0 INZ(64)
     D*** File Status Flags for open() and fcntl()
     D O_NONBLOCK      S             10I 0 INZ(128)
     D O_APPEND        S             10I 0 INZ(256)
     D*** oflag Share Mode Values for open()
     D O_SHARE_NONE    S             10I 0 INZ(2000000)
     D O_SHARE_RDONLY  S             10I 0 INZ(0200000)
     D O_SHARE_RDWR    S             10I 0 INZ(1000000)
     D O_SHARE_WRONLY  S             10I 0 INZ(0400000)
     D*** file permissions
     D S_IRUSR         S             10I 0 INZ(256)
     D S_IWUSR         S             10I 0 INZ(128)
     D S_IXUSR         S             10I 0 INZ(64)
     D S_IRWXU         S             10I 0 INZ(448)
     D S_IRGRP         S             10I 0 INZ(32)
     D S_IWGRP         S             10I 0 INZ(16)
     D S_IXGRP         S             10I 0 INZ(8)
     D S_IRWXG         S             10I 0 INZ(56)
     D S_IROTH         S             10I 0 INZ(4)
     D S_IWOTH         S             10I 0 INZ(2)
     D S_IXOTH         S             10I 0 INZ(1)
     D S_IRWXO         S             10I 0 INZ(7)
     D*** misc
     D O_TEXTDATA      S             10I 0 INZ(16777216)
     D O_CODEPAGE      S             10I 0 INZ(8388608)
     D*****************************************************************
     D* DEFINITIONS
     D*****************************************************************
     D*** divers
     D nomfichier      S            255A
     D lgfichier       S             10I 0
     D AsciiCodePage   S             10U 0 INZ(1252)
     D FullName        S            512A
     D ReturnInt       S             10I 0
     D***
     D File_Hdl        S             10I 0
     D Byteswrt        S             10I 0
     D EOR             S              2A   Inz(X'0D25')
     D Null            S              1A   Inz(X'00')
     D ligne           S          32767
      **********************************************************************
      * variable retour pour le format RTVM0300
     Dmessage_rt       DS         32767
     D  byte_retour                  10I 0
     D  byte_dispo                   10I 0
     D  msgid_rt                      7    overlay(message_rt : 27)
     D  msg_offset                   10I 0 overlay(message_rt : 65)
     D  msg_retour                   10I 0 overlay(message_rt : *next)
     D  msg_dispo                    10I 0 overlay(message_rt : *next)
     D  msg2_offset                  10I 0 overlay(message_rt : 77)
     D  msg2_retour                  10I 0 overlay(message_rt : *next)
     D  msg2_dispo                   10I 0 overlay(message_rt : *next)
     D  data                       9999

     d msg1            S            256      d msg2            S           9000

      * divers paramètres      Dmessage_rt_lg    S             10I 0 inz(%size(message_rt))      Dformat           S              8    inz('RTVM0300')      dmsgid            S              7      dmsgf             S             20    inz('QCPFMSG   QSYS')      dmsgdta           S              1      dmsgdta_lg        S             10I 0 inz(0)      dremplace_var     S             10    inz('*NO')      dremplace_spc     S             10    inz('*NO')
     Derror_code       DS      D  err_lg                       10I 0 inz(%size(error_code))      D  err_retour                   10I 0      D  err_filler                    1      D  err_msgid                     7
     Doption           S             10    inz('*FIRST')      Dmsg_ccsid        S             10I 0 inz(0)      Ddta_ccsid        S             10I 0 inz(0)
      * prototype d'appel à l'API

     Drtvmsg           PR                  EXTPGM('QMHRTVM')
     D                             9999
     D                               10I 0
     D                                8
     d                                7
     d                               20
     d                                1
     d                               10I 0
     d                               10
     d                               10
     D                               16
     D                               10
     D                               10I 0
     D                               10I 0
      * on recoit msgf et bibliothèque en paramètre
     C     *entry        plist
     C                   parm                    p_msgf           10
     C                   parm                    p_msgfl          10
     C                   parm                    p_nomfic        255
      /free
       msgf = p_msgf + p_msgfl;
       nomfichier = p_nomfic  ;

       lgfichier = %Len(%Trimr(nomfichier)) ;        // Ouverture du fichier         FullName = %TRIMR(nomfichier) + Null;         file_Hdl = open(%ADDR(FullName)                       : O_CREAT + O_WRONLY + O_TRUNC + O_CODEPAGE                       : S_IRWXU + S_IROTH                       : AsciiCodePage);         ReturnInt = close(file_Hdl);         // 2ème ouverture         file_Hdl = open(%ADDR(FullName) : O_TEXTDATA + O_RDWR);        exsr lecture;        option = '*NEXT';        dow byte_dispo > 0;
         msg1 = %subst(message_rt : msg_offset + 1 : msg_retour);          ligne = '"' + msgid_rt + '";"' + %trim(msg1) + '"';
         if msg2_offset > 0;             msg2 = %subst(message_rt : msg2_offset + 1 : msg2_retour);             ligne = %trimr(ligne) + ';"' + %trim(msg2) + '"';          endif;
        //Ecriture IFS
          ligne = %Trimr(ligne) + EOR;
           byteswrt = write(file_Hdl : %ADDR(ligne)
                             : %LEN(%TRIMR(ligne))) ;
           // positionnement sur le message suivant
            msgid = msgid_rt;
            exsr lecture;
       enddo;
       ReturnInt = close(file_Hdl);
       *inlr = *on;

        // S-PGM
        //   appel à l'API.        begsr lecture;         rtvmsg(message_rt : message_rt_lg : format : msgid : msgf : msgdta :                 msgdta_lg  : remplace_var : remplace_spc : error_code :                 option     : msg_ccsid    : dta_ccsid);        endsr;       /end-free
Retourner au Début

Copyright © 1995,2002 VOLUBIS