Travailler avec les sockets IP

BoTTom |    Changer de couleur
 
 ILE permet d'utiliser en RPG 4 des fonctions écrites ou destinées au C/400.
 
  le prototypage RPG 4 va permettre de réaliser cela.
 
 correspondance des paramètres
 ------------------------------
 
 quelques rappels
 
 EN C, le passage de paramètres se fait par défaut par valeur
 
 EN RPG  le passage de paramètres se fait par défaut par référence
         (on passe un pointeur, comme en C par int*), pour un passage
         de paramètre par valeur, indiquer VALUE
 
 EN C, les chaines de caractères sont terminées par x'00', en RPG elles
        sont à taille fixe, sans terminaison, l'option OPTIONS(*STRING)
        assure la correspondance, et si la paramètre envoyé est une chaine
        , GAP stocke l'information en mémoire temporaire, ajoute un zéro
        hexadécimal et transmet l'adresse (le pointeur).
 


|    Changer de couleur
 
 +-------------+------------+--------------------------------------------+
 +     C       +  RPG 4     + Mots-clés                                  +
 +-------------+------------+--------------------------------------------+
 + int, long   +  10I 0     + VALUE                                      +
 +-------------+------------+--------------------------------------------+
 + unsigned int+  10U 0     + VALUE                                      +
 +-------------+------------+--------------------------------------------+
 + double      +   8F 0     + VALUE                                      +
 +-------------+------------+--------------------------------------------+
 + char        +   1A       + VALUE (il s'agit d'UN octet seul)          +
 +OU ----------+------------+--------------------------------------------+
 + char        +  10U 0     + VALUE                                      +
 +-------------+------------+--------------------------------------------+
 + short       +  10i 0     + VALUE                                      +
 +-------------+------------+--------------------------------------------+
 + int*        +  10i 0     +                                            +
 +-------------+------------+--------------------------------------------+
 + unsigned*   +  10U 0     +                                            +
 +-------------+------------+--------------------------------------------+
 + double*     +   8F 0     +                                            +
 +-------------+------------+--------------------------------------------+


|    Changer de couleur
 
 +-------------+------------+--------------------------------------------+
 +     C       +  RPG 4     + Mots-clés                                  +
 +-------------+------------+--------------------------------------------+
 + char*       + xxxA       + OPTIONS(*STRING)                           +
 +OU ----------+------------+--------------------------------------------+
 + char*       +    *       + VALUE (il faudra utiliser %ADDR().)        +
 +-------------+------------+--------------------------------------------+
 + void*       +    *       + VALUE                                      +
 +(pointeur)   +            +                                            +
 +-------------+------------+--------------------------------------------+
 + (*)         +    *       + VALUE  PROCPTR                             +
 +(fonction)   +            +                                            +
 +-------------+------------+--------------------------------------------+
 
 L'utilisation du mot-clé CONST sera souvent un plus pour les données
  élémentaires, par exemple si une fonction C admet un integer, le prototype
  ..................................................................
  :  D mafonctionC     PR                  extproc('maFonctionC')  :
  :  D                               10i 0 CONST                   :
  :................................................................:
 permet d'utiliser du décimal paquet, le compilateur assurant la conversion.


|    Changer de couleur
 par exemple, la définition suivante
 
  double cos(double)
 
 se traduit en RPG , par :
 
  ..................................................................
  :  D cosinus         PR             8F 0 extproc('cos')          :
  :  D                                8F 0  VALUE                  :
  :................................................................:
 
 et celle ci (utilisant des chaînes)
 
  char* strcpy (char* str1, str2)
 
 se traduit en RPG , par :
 
  ..................................................................
  :  D stringcopy      PR              *   extproc('strcpy')       :
  :  D  str1                         25A    OPTIONS(*STRING)       :
  :  D  str2                         25A    OPTIONS(*STRING)       :
  :................................................................:


|    Changer de couleur
 Exemple d'un pgm complet utilisant atoi (alpha -> int) et atof (->flot)
 -----------------------------------------------------------------------
 
H bnddir('QC2LE') DFTACTGRP(*NO) ACTGRP(*CALLER)
D atoi            pr            10i 0 extproc('atoi')
D  num                            *   options(*string) value
D atof            pr             8f   extproc('atof')
D  num                            *   options(*string) value
D i               s             10i 0
D p               s             13p 7
C                  movel     '-100  '      num               6
C                  eval      i = atoi(%trim(num))
 *
 *  I = -100
C                   eval(h)   p = atof(%trim(num))
 *
 *  P = -000100.0000000
C                   movel     '-5.67 '      num               6
C                   eval(h)   p = atof(%trim(num))
 *
 *  P = -000005.6700000
                   return


|    Changer de couleur
 
Pour une valeur retour de type chaine, nous avons deux possibilités :
 
 1/ baser une variable sur le pointeur recu :
  ..................................................................
  :  D ptr             S               *                           :
  :  D chaine          S             50A   BASED(ptr)              :
  :                                                                :
  :   /free                                                        :
  :     ptr = stringcopy(chaine1 : chaine2) ;                      :
  :     if chaine = *blanks;                                       :
  :................................................................:
 
 2/ Utiliser la fonction RPG %str()
  ..................................................................
  :  D ptr             S               *                           :
  :  D chaine          S             50A                           :
  :                                                                :
  :   /free                                                        :
  :     ptr = stringcopy(chaine1 : chaine2) ;                      :
  :     eval chaine = %str(ptr)                                    :
  :................................................................:


|    Changer de couleur
 
 Certaines fonctions utilisent des variables globales, par exemple system()
 
H bnddir('QC2LE') DFTACTGRP(*NO) ACTGRP(*CALLER)
 
D Exec            pr            10i 0 Extproc('system')
D  cmd                            *   options(*string) value
 
D ErrMsgID        S              7    IMPORT('_EXCP_MSGID')
D retour          S             10I O
 
 /free
 
   retour = Exec('DLTSPLF *SELECT');
 
   if retour > 0;
 
      if ErrMsgID = 'CPF....' ;
 
         .../...
 
 /end-free


|    Changer de couleur
 
Tout ceci permet d'utiliser les sockets IP, routines de base du protocole,
 destinées à établir un dialogue réseau de programme à programme.
 
Un socket est au réseau ce qu'un fichier est au disque dur
 ==> un niveau d'abstraction
 
Vous devez être familier avec les concepts suivants
 
 -Protocole : TCP/UDP fonctionnant tous les deux sur IP ou ICMP
 
 -Adresse IP: identifiant réseau d'un poste (par exemple 192.168.1.2)
 
 -DNS       : mechanisme permettant d'établir la correspondance entre
              un nom usuel et une adresse IP
 
 -Port      : l'adresse IP identifant le système, le n° de port identifie
               l'application (sur un serveur à l'écoute, souvent < 1024)
               la connexion (sur un client, port dynamique > 1024)
 
 -socket    : flux (comme un fichier stream) représentant le réseau
 


|    Changer de couleur
 
 
   inet_addr() convertit une adresse IP du format "clair", en binaire
                format utilisé par les sockets
 
  ..................................................................
  :  D inet_addr       PR            10U 0 extproc('inet_addr')    :
  :  D   char_addr                     *    VALUE option(*string)  :
  :................................................................:
 
 
 
   gethostbyname retrouve l'adresse IP correspondant au nom de host
 
  ..................................................................
  :  D gethostbyname   PR              *   extproc('gethostbyname'):
  :  D   host_name                     *    VALUE option(*string)  :
  :................................................................:
 
 
  il faut renseigner le fichier host(CFGTCP/10) ou le serveur DNS(CFGTCP/12)
 


|    Changer de couleur
Exemple :
 
      /copy socket_H
 
   D user_addr       s            200A
   D addr            s             10U 0
 
   **DS en retour de GetHostByName (déja déclarée dans socket_H)
   D*p_hostent       S               *
   D*hostent         DS                  Based(p_hostent)
   D*  h_name                        *
   D*  h_aliases                     *
   D*  h_addrtype                   5I 0
   D*  h_length                     5I 0
   D*  h_addrlist                    *
   D*p_h_addr        S               *   Based(h_addrlist)
   D*h_addr          S             10U 0 Based(p_h_addr)
 
 Rappel : avec le mot-clé BASED la variable recouvre l'adresse mémoire
           indiquée par le pointeur passé en paramètre.
 
          ici, il s'agit d'un pointeur basé sur un pointeur !!


|    Changer de couleur
 
 Utilisation
 
    /free
          addr = inet_addr(%trimr(user_addr));
 
          if (addr = INADDR_NONE);
 
              p_hostent = gethostbyname(%trimr(user_addr));
              if (p_hostent = *NULL);
                  DSPLY 'Host lookup failed.'
                  return;
              else;
                  addr = h_addr;
              endif;
 
          endif;
    /end-free
 
      toutes les constantes (INADDR_NONE) sont fournies dans SOCKET_H
 
 


|    Changer de couleur
  getservbyname retrouve le port utilisé pour un service donné
 
 ..................................................................
  : D getservbyname   PR              *   extproc('getservbyname'):
 :  D   service_name                  *    VALUE option(*string)  :
 :  D   protocolname                  *    VALUE option(*string)  :
 :................................................................:
 
   D*p_servent       S               *
   D*servent         DS                  Based(p_servent)
   D*  s_name                        *
   D*  s_aliases                     *
   D*  s_port                      10I 0
   D*  s_proto                       *
 
    /free
       p_servent = getservbyname('smtp': 'tcp');
       if (p_servent <> *NULL);
            port = s_port;
        else;
            port = 25;
        endif;


|    Changer de couleur
 
 Ensuite vous devez :
 
  1/ créer le socket
  2/ vous connecter au système distant
 
 Création d'un socket
 ..................................................................
 : D socket          PR            10I 0 Extproc('socket')        :
 : D   AddrFamilly                 10I 0 Value                    :
 : D   SocketType                  10I 0 Value                    :
 : D   Protocol                    10I 0 Value                    :
 ..................................................................
 
 AddrFamilly : AF_INET  (2) = IP/V4
               AF_INET6     = IP/V6 (non traité dans ce cours)
 
 SocketType  : SOCK_STREAM (1) = TCP
               SOCK_DGRAM  (2) = UDP
 
 Protocol    : IPPROTO_IP  (O) = Choisir le protocole en fonction du type
                                  (paramètre précédent)


|    Changer de couleur
 
Connexion
..................................................................
: D connect         PR            10I 0 Extproc('connect')       :
: D   Sock_Desc                   10I 0 Value                    :
: D   P_sockAddr                    *   Value                    :
: D   AddressLen                  10I 0 Value                    :
..................................................................
 
 le 1er paramètre est le descripteur retourné par l'API "socket"
 
 le 2ème est un pointeur (%ADDR) vers une structure décrivant le socket
 
    D p_sockaddr      S               *
 
    D sockaddr_in     DS                  based(p_sockaddr)
    D   sin_Family                   5I 0
    D   sin_Port                     5U 0
    D   sin_addr                    10U 0
    D   sin_zero                     8A
 
 le troisième indique la longueur (%SIZE) du 2eme


|    Changer de couleur
 
Exemple :
 
     D s               s             10I 0
     D connto          ds                  likeds(sockaddr_in)
 
      /free
          s = socket(AF_INET: SOCK_STREAM: IPPROTO_TCP);
          if (s = -1);
             DSPLY   'socket failed !';
             return;
          endif;
 
          connto = *ALLx'00';
          connto.sin_family = AF_INET;        // toujours socket_H
          connto.sin_addr   = addr;           //  inet_addr ou gethostbyname
          connto.sin_port   = port;           //  getservbyname
          if ( connect(s: %addr(connto): %size(connto)) = -1 );
                callp close(s);
                DSPLY   'Connect failed !';
                return;
          endif;


|    Changer de couleur
 
 Envoi/Réception
 ..................................................................
 : D Send            PR            10I 0 Extproc('send')          :
 : D   Sock_Desc                   10I 0 Value                    :
 : D   P_buffer                      *   Value                    :
 : D   BufferLen                   10I 0 Value                    :
 : D   flag                        10I 0 Value                    :
 ..................................................................
 ..................................................................
 : D Recv            PR            10I 0 Extproc('recv')          :
 : D   Sock_Desc                   10I 0 Value                    :
 : D   P_buffer                      *   Value                    :
 : D   BufferLen                   10I 0 Value                    :
 : D   flag                        10I 0 Value                    :
 ..................................................................
 
 Sock_Desc : le descripteur retourné par "socket"
 P_buffer  : pointeur vers les données à lire/à écrire
              attention à la conversion EBCDIC/ASCII si besoin (autre OS)   
 BufferLen : longueur (%size) du buffer
 flag      : ne sert pas transmettre à 0 


|    Changer de couleur
 
Exemple d'envoi :
 
     D cmd             s             10
     D lencmd          S             10i 0
 
 
 
      /free
 
          cmd = 'HEURE' ;
 
          lencmd = send(s : %addr(cmd) : %len(%trimr(cmd)) : 0);
          if lencmd < %len(%trimr(cmd)) ;
                DSPLY 'Erreur lors de l''envoi';
          endif;
 
      /end-free
 
 
 
 


|    Changer de couleur
 
Exemple de réception (chaîne de 6) :
 
     D temp            s             10
     D len             S             10i 0
     D reponse         S              6    varying
 
      /free
          reponse = ' ';
                                 //on est pas sur que le 6 octets arrivent
          dou %len(reponse) = 6;  // d'un coup (suivant charge réseau)
 
            len = recv(s : %addr(temp) : %size(temp) : 0);
            if len = -1;
               DSPLY 'Erreur lors de la réception ;
            endif;
            if len = 0;  //plus rien
               leave;
            endif;
            reponse = reponse + %subst(temp : 1 : len);
          enddo
      /end-free


|    Changer de couleur
 
Enfin, le socket doit être fermé explicitement, la fin de pgm ne suffit pas.
  un socket ne peut jamais être réutilisé (sauf option explicite)
 
  ..................................................................
  : D Close           PR            10I 0 Extproc('close')         :
  : D   Sock_Desc                   10I 0 Value                    :
  ..................................................................
 
  retourne -1 en cas d'erreur, 0 dans le cas contraire.
    vous pouvez ne pas recevoir la valeur retour : callp close(s)
 
Pour plus de précision vous pouvez récuperer le code erreur (en général)
 par la routine standard "__errno":
 ..................................................................
 : D errptr                          *                            :
 : D errno                         10I 0 based(errptr)            :
 : D sys_errno       PR            10I 0 Extproc('__errno)        :
 :                                                                :
 :  /free                                                         :
 :    errptr = sys_errno();                                       :
 ..................................................................


|    Changer de couleur
 
 Pour faire un serveur, vous avez deux possibilités :
 
 1/ méthode traditionnelle, tout faire
 
 2/ utiliser le serveur de serveurs INETD (que nous verrons ensuite)
 
 
Pour tout faire soi même :
 
 1/ (facultatif) récupérer le port serveur par getservbyname()
 
 2/ création d'un socket
 
 3/ associer le socket au port par bind()
 
 4/ lancer l'API listen() pour passer le port à l'écoute
 
 
 5/ utiliser accept() en attendant une connexion (nouveau socket entrant)
 
 6/ clore le socket du 5/ et recommencer


|    Changer de couleur
 
 ..................................................................
 : D bind            PR            10I 0 ExtProc('bind')          :
 : D socket                        10I 0 Value                    :
 : D local_addr                      *   Value                    :
 : D addresslen                    10I 0 Value                    :
 :................................................................:
 
 
 ..................................................................
 : D listen          PR            10I 0 ExtProc('listen')        :
 : D socket_desc                   10I 0 Value                    :
 : D back_log                      10I 0 Value                    :
 ..................................................................
 
 
 ..................................................................
 : D accept          PR            10I 0 ExtProc('accept')        :
 : D socket_desc                   10I 0 Value                    :
 : D adress                          *   Value                    :
 : D addresslen                    10I 0 Value                    :
 ..................................................................


|    Changer de couleur
Cette technique permet le dialogue avec un client.
 
 Si vous souhaitez accepter la connexion de multiples clients, vous devez
  utiliser l'API select() ou bien utiliser INETD .
 
 Inet daemon est le serveur de serveurs, il va gérer
  les connexion entrantes (multiples)
 
  - créer un socket pour chaque connexion (vous manipulez un socket à 0)
  - soumettre votre programme déja connecté
 
 Vous devez :
 
 Enregistrez votre service dans la table des services (CFGTCP option 21/1)
 
   ADDSRVTBLE SERVICE('monservice') PORT(1234) PROTOCOL('tcp')
 
 Editer '/QIBM/USERDATA/OS400/INETD/inetd.conf' pour ajouter
 
 monservice   stream   tcp nowait QUSER /QSYS.LIB/MABIB.LIB/MONPGM.PGM
 
 lancer INETD par STRTCPSVR SERVER(*INETD)


|    Changer de couleur
Exemple de serveur utilisant INETD
 
     H DFTACTGRP(*NO) BNDDIR('QC2LE')
     D CMD             S              4    varying
     D reponse         S             10
     Ds                S             10I 0
     Dlen              S             10I 0
     Dtemp             S              4
 
      /copy socket_H
      /free
          dsply 'serveur lancé' 'QSYSOPR';
          s = 0;
          CMD = '';
 
          dou %len(CMD) = 4;
           len = recv(s : %addr(temp) : %size(temp) : 0);
           if len = -1;
             DSPLY 'Erreur lors de la réception' 'QSYSOPR';
           endif;
           CMD = CMD + %subst(temp : 1 : len);
          enddo;


|    Changer de couleur
 
          if CMD = 'DATE';
             reponse = %char(%date());
          ENDIF;
 
          if CMD = 'TIME';
             reponse = %char(%time());
          ENDIF;
 
          reponse  = reponse + x'0a';
          len = send(s : %addr(reponse) : %len(%trimr(reponse)) : 0);
          callp close (s);
          *inlr = *on;
 
      /end-free
 
 
 
    ci dessous le client (utilisant ces propres fonction SendQ et GetR)
 
 
 


|    Changer de couleur
      *
     H dftactgrp(*no)
 
      /copy socket_H
 
     D SendQ           PR            10I 0
     D   sock                        10I 0 value
     D   data                      1024A   value
 
     D GetR            PR            10
     D   sock                        10I 0 value
 
     D addr            s             10U 0
     D port            s              5U 0
     D s               s             10I 0
     D connto          ds                  likeds(sockaddr_in)
     D attente         s              1
      /free
          // ---------------------------------------------------
          //  recherche adresse ip (ici locale) et port
          // ---------------------------------------------------
 


|    Changer de couleur
          p_hostent = gethostbyname('LOOPBACK');
          if (p_hostent = *NULL);
             DSPLY  'Host lookup failed.' ;
             return;
          else;
             addr = h_addr;
          endif;
 
          port = 666;
          // ---------------------------------------------------
          //   creation socket
          // ---------------------------------------------------
 
          s = socket(AF_INET: SOCK_STREAM: IPPROTO_TCP);
          if (s = -1);
             DSPLY  'socket failed!' ;
             return;
          endif;
 
          // ---------------------------------------------------
          //   connection
          // ---------------------------------------------------


|    Changer de couleur
 
          connto = *ALLx'00';
          connto.sin_family = AF_INET;
          connto.sin_addr   = addr;
          connto.sin_port   = port;
 
          if ( connect(s: %addr(connto): %size(connto)) = -1 );
             callp close(s);
             DSPLY  'Connect failed!' ;
             return;
          endif;
 
          SendQ(s: 'TIME');
          DSPLY   GetR(s) '*EXT' attente; // affichage écran pour test
          callp close(s);
          *inlr = *on;
 
      /end-free
 
      *+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
      * Envoi de la question
      *+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++


|    Changer de couleur
     P SendQ           B
     D SendQ           PI            10I 0
     D   sock                        10I 0 value
     D   data                      1024A   value
 
     D len             s             10I 0
      /free
 
         len = %len(%trimr(data));
         return send(sock: %addr(data): len: 0 );
 
      /end-free
 
     P                 E
 
      *+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
      * Reception de la réponse
      *
      * On part du principe que la réponse fait 10
      *  sinon il faut gérer un caractère de fin, par exemple
      *         LF (ASCII x'0a') ou CRLF (EBCDIC X'OD25')
      *+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++


|    Changer de couleur
     P GetR            B
     D GetR            PI            10
     D   sock                        10I 0 value
 
     D temp            s             10A
     D data            s             10    VARYING
     D reply           s             10
     D len             s             10I 0
 
      /free
         dou %len(Data) = 10 or %scan(X'0a' : data) > 0;
 
           len = recv(sock : %addr(temp) : %size(temp) : 0);
           if len = -1;
             DSPLY 'Erreur lors de la réception ;
             return 'Err';
           endif;
           if  len = 0 or %subst(temp : len: 1) = x'0a';
             leave;
           ENDIF;
           DATA = DATA + %subst(temp : 1 : len);
         enddo;


|    Changer de couleur
 
         monitor;
            reply = %subst(data:1:%len(data));
         on-error;
            reply = 'Erreur';
         endmon;
 
         return reply;
      /end-free
     P                 E
 
 il est ainsi plus simple de gérer la conversion ASCII/EBCDIC dans les
  fonctions SendQ et GetR si vous dialoguez avec une machine en ASCII.
 
 1ere possibilité QDCXLATE 
  D QDCXLATE        PR                  ExtPgm('QDCXLATE')
  D   Size                         5P 0 const
  D   Data                     32702A   options(*varsize)
  D   Table                       10A   const
 puis
 
   QDCXLATE( datalen : data: 'QTCPEBC' ); // 'QTCPASC', lors de l'envoi


|    Changer de couleur
 
ca marche bien avec des données US (code page 37) mais mal avec nos
 caractères accentués.
 
il est préférable, alors, d'utiliser iconv() (standard du langage C)
 
 H DFTACTGRP(*NO)
  *------------------------------------------------------------------
  * Prototype for Code Conversion - Open
  *------------------------------------------------------------------
 d IConvOpen       PR            52A   ExtProc('QtqIconvOpen')
 d                                 *   Value options(*string)
 d                                 *   Value options(*string)
  *------------------------------------------------------------------
  * Prototype for Code Conversion
  *------------------------------------------------------------------
 d IConv           PR            10i 0 ExtProc('iconv')
 d                               52a   Value
 d                                 *   Value
 d                               10I 0
 d                                 *   Value
 d                               10I 0


|    Changer de couleur
  **************************************************************************
  *  Code Page (iconv_t, réponse de IConvOpen, argument à iconv)
  **************************************************************************
 d ToAscii         DS
 d  ICORV_A                1      4b 0
  *                  return value to indicate if error occurred
 d  ICOC_A                 5     52b 0 DIM(00012)
 
  *
 d ToEbcdic        DS
 d  ICORV_E                1      4b 0
  *                  return value to indicate if error occurred
 d  ICOC_E                 5     52b 0 DIM(00012)
 
  * divers variables
 Dp_InBuff         S               *
 Dp_OutBuff        S               *
 DInBytesLeft      S             10I 0
 DOutBytesLeft     S             10I 0
 Dp_InBytes        S               *
 Dp_OutBytes       S               *
 DRc               S             10I 0


|    Changer de couleur
 
 d p_Qascii        S               *   inz(%addr(Qascii))
 d Qascii          DS            32
 d  asciiCP                1      4b 0 inz(01252) <- ANSI(Windows),819=ASCII
 d  asciiCA                5      8b 0 inz(0)
 d  asciiSA                9     12b 0 inz(0)
 d  asciiSS               13     16b 0 inz(1)
 d  asciiIL               17     20b 0 inz(0)
 d  asciiEO               21     24b 0 inz(1)
 d  asciiR                25     32a   inz(*allx'00')
 
  *
 d p_Qebcdic       S               *   inz(%addr(Qebcdic))
 d Qebcdic         DS            32
 d  ebcdicCP               1      4b 0 inz(00297) <- EBCDIC Français
 d  ebcdicCA               5      8b 0 inz(0)
 d  ebcdicSA               9     12b 0 inz(0)
 d  ebcdicSS              13     16b 0 inz(1)
 d  ebcdicIL              17     20b 0 inz(0)
 d  ebcdicEO              21     24b 0 inz(1)
 d  ebcdicR               25     32a   inz(*allx'00')
 


|    Changer de couleur
  * Initialisation EBCDIC/ASCII
 c                   eval      ToAscii  = IConvOpen(p_Qascii:
 c                                        p_Qebcdic)
 c                   if        ICORV_A = -1
  * erreur
 c                   DSPLY     'Erreur à l''initialisation'
 c                   endif
 
  *
  * conversion EBCDIC/ASCII
 c                   eval      p_InBuff  = %addr(TXTIN)
 c                   eval      p_OutBuff = %addr(TXTOUT)
 c                   eval      InBytesLeft = %len(%trim(TXTIN))
 c                   eval      OutBytesLeft = %len(TXTOUT)
 c                   eval      rc = IConv(ToAscii:
 c                                        %addr(p_InBuff):
 c                                        InBytesLeft:
 c                                        %addr(p_OutBuff):
 c                                        OutBytesLeft)
 c                   if        ICORV_A > 0
 c                   DSPLY     'Erreur à la conversion'
 c                   endif


|    Changer de couleur
  * Initialisation ASCII/EBCDIC
 c                   eval      ToEbcdic = IConvOpen(p_Qebcdic:
 c                                        p_Qascii)
 c                   if        ICORV_E = -1
  * erreur
 c                   DSPLY     'Erreur à l''initialisation'
 c                   endif
 
  *
  * conversion ASCII/EBCDIC
 c                   eval      p_InBuff  = %addr(TXTIN)
 c                   eval      p_OutBuff = %addr(TXTOUT)
 c                   eval      InBytesLeft = %len(%trim(TXTIN))
 c                   eval      OutBytesLeft = %len(TXTOUT)
 c                   eval      rc = IConv(ToEbcdic:
 c                                        %addr(p_InBuff):
 c                                        InBytesLeft:
 c                                        %addr(p_OutBuff):
 c                                        OutBytesLeft)
 c                   if        ICORV_E > 0
 c                   DSPLY     'Erreur à la conversion'
 c                   endif


|    Changer de couleur
 
 A chaque utilisation de iconv_open doit être associée iconv_close
 
  dont voici le prototype :
 
 
  *------------------------------------------------------------------
  * Prototype for Code Conversion - Close
  *------------------------------------------------------------------
 d IConvClose      PR            10I 0 ExtProc('iconv_close')
 d                               52A   Value
 
  * réutiliser ensuite le résultat retourné par iconv_open
 
 c                   eval      rc = IConvClose(ToEbcdic)
 c                   eval      rc = IConvClose(ToAscii)
 
   avant de terminer votre programme
 
 C                   eval      *inlr = *on
 
 


|    Changer de couleur
 
Quelques références :
 
 Sites IBM
 ----------
 
 la documentation à Information Center
 
http://publib.boulder.ibm.com/infocenter/iseries/v5r4/topic/apis/unix8.htm
http://publib.boulder.ibm.com/infocenter/iseries/v5r4/topic/apis/nls3.htm
 
 ce redbook sur RPG-IV
 
http://www.redbooks.ibm.com/Redbooks.nsf/RedbookAbstracts/sg245402.html?Open
 
 
 Autres sites
 ------------
 
Scott Klement (proposant un SAVF avec qq exemples, dont SOCKET_H)
 
http://www.scottklement.com/rpg/socktut/index.html





©AF400