![]()
![]()
![]()
![]()
![]()
Next: Recherche dans une liste Up: Premier programmes Previous: Entées / sorties   Contents   Index
Subsections
- Fonctions d'entrée / sorties de bas niveau
- Caractère spéciaux
- Sortie formatée
- Port en mémoire
- Répertoires locaux
- Informations sur les fichiers d'un répertoire
- Port en lecture ET écriture
- Connexion réseau
- Connexions FTP/HTTP
- Exemple
Plus loin avec les entrées/sorties Pour le langage Scheme, un port est associé à un fichier connu par son nom.
L'environnement OpenScheme étend la notion de port aux ports virtuels. Parmi les ports virtuels, on trouve les chaînes de caractères, les connexions FTP ou HTTP... De plus, l'environnement propose une puissante fonction de sortie formatée.
Fonctions d'entrée / sorties de bas niveau
Dans la spécification du langage Scheme, les ports ne peuvent être accédés que de manière séquentielle de manière à lire des caractère ou des objets Scheme. OpenScheme permet de lire toutes sorte de données et de le faire en accès direct.
A chaque port est associé un pointeur de fichier. Pour les fichiers en correspondance avec un fichier sur le disque, ce pointeur de fichier peut être consulté et/ou déplacé à loisir, permettant un accès direct à toutes les parties du fichier.
La fonction :
(port-tell [port])retourne la valeur du pointeur de fichier sous la forme d'un entier. Si le port est omis, le port d'entrée standard est utilisé. La fonction :
(port-seek n [port])permet de modifier la valeur d'un pointeur de fichier. Si
portn'est pas renseigné, le port d'entrée standard est utilisé. La fonction :(port-length [port])retourne la valeur maximale d'un pointeur de fichier. Cette valeur correspond en fait à la taille en octets du fichier. Si le port n'est pas indiqué, le port d'entrée standard est utilisé.
La fonction :
(port-read n [port])lit
noctets d'un fichier et retourne la chaîne de caractères formées des octets lus à partir du pointeur de fichier. Siportn'est pas indiqué, le port d'entrée standard est utilisé. Enfin, la fonction :(port-write str n [port])écrit
noctets de la chaîne de caractèresstrà la position du pointeur de fichier d'un port. Siportest omis, le port de sortie standard est utilisé.
Caractère spéciaux
Les chaînes de caractères destinées aux sorties peuvent contenir tous les caractères imprimables classiques. OpenScheme reconnaît aussi des caractères spéciaux. Ceci sont préfixés par le caractères d'échappement anti-slash :
Caractère Signification \nSaut de ligne \rDébut de ligne \tTabulation \bSignal sonore Par exemple :
Osm> (display "123\r456\t789\n012\n") 456 789 012 => #unspecified
Sortie formatée
La fonction
formatpermet l'affichage formaté des ses arguments. Sa syntaxe générale est :(format port pilote arguments...)Les arguments :
Portest soit un port de sortie, soit la valeur#tpour désigner le port de sortie courant, soit la valeur#fpour indiquer que la sortie doit s'effectuer dans une chaîne de caractères qui sera retournée.
piloteest la chaîne de format proprement dite. Tous les caractères qu'elle contient sont affichés tel quels. Certains caractères préfixés par tilde indique que l'argument correspondant doit être affiché selon la spécification désirée. Les spécifications sont :
~aou~Aest remplacé par la représentation imprimable de l'argument correspondant.~sou~Sest remplacé par la représentation réelle de l'argument correspondant.~dou~Dest remplacé par la représentation imprimable de l'argument correspondant. Lorsque l'argument est une structure cyclique, le cycle est cassé et remplacé par trois points.~wou~West remplacé par la représentation réelle de l'argument correspondant dans lequel les cycles sont cassés et remplacés par trois points.~xor~Xest remplacé par la représentation en hexadécimal de l'objet (valeur ou référence en mémoire).~~est remplacé par un simple tilde.Par exemple :
Osm> (format #f "A test.") => A test.#unspecified Osm> (format #f "A ~a." "test") => "A test."#unspecified Osm> (define l '(1 2 3)) => #unspecified Osm> (set-car! (cdr l) l) => #unspecified ; a recursive list is built Osm> (format *current-output-port* "list = ~w\n) (1 ... 3) => #unspecified Osm> (display l) => Segmentation fault
Port en mémoire
Les ports virtuels ouverts en mémoire permettent de bénéficier des fonctions standard d'entrée / sortie. Le port en mémoire peut être ouvert en lecture avec :
(open-input-string chaîne)La fonction retourne un port d'entrée accessible par les fonctions standard :
Osm> (define port (open-input-string "12345")) => #unspecified Osm> (let loop ([i 1]) (let ([c (read-char port)]) (if (not (eof-object? c)) (begin (format #t "~a: ~a\n" i c) (loop (+ i 1)))))) 1: #\1 2: #\2 3: #\3 4: #\4 5: #\5 => #unspecified Osm> (close-input-port port) => #unspecifiedLorsque tous les caractères ont été lus, les fonctions de lectures retournent la fin de fichier qui peut être testée avec la fonction
eof-object?. Le port ouvert se referme avec la fonction standard.Les fonctions
call-with-input-stringetwith-input-from-stringsont aussi disponibles et fonctionnent comme leurs homologues opérant sur les fichiers.La fonction
input-string?retourne#tsi son argument est un port d'entrée en mémoire et#fsinon.Un port en mémoire en sortie est ouvert avec la fonction :
(open-output-string)Cette fonction retourne un port de sortie sur lequel les fonctions de sorties standard sont utilisables. Lorsque le travail est fini, il est possible de convertir le port en chaîne de caractères avec la fonction get-output-string.
Osm> (define port (open-output-string)) => #unspecified Osm> (display "message" port) => #unspecified Osm> (display "- autre message" port) => #unspecified Osm> (get-output-string port) => "message - autre message" Osm> (close-output-port port) => #unspecifiedLe port ouvert se referme avec la fonction standard.
Les fonctions
call-with-output-stringetwith-output-to-stringse comportent comme leurs homologues sur les fichiers.
Répertoires locaux
Les fonctions d'ouverture de port d'OpenScheme opèrent aussi sur les répertoires. Le comportement des fonctions d'entrée / sorties voient leur comportement adapté à ce type de port.
Un répertoire est ouvert simplement en indiquant son nom à l'une des fonctions opérant à l'ouverture des fichiers. Par exemple :
Osm> (define tmp (open-input-port "/tmp")) => #unspecifiedLorsque le port associé à un répertoire est ouvert en lecture, il retourne les noms des fichiers contenus dans ce répertoire, séparés par des retour chariot :
Osm> (let loop ([rep (read-line tmp)]) (if (not (eof-object? rep)) (begin (format #t "entrée: ~a\n" rep) (loop (read-line tmp))))) entrée: 93499~df entrée: 9e3499~df.tmp entrée: 943327993-gtkrc-41306685 entrée: IMG_PARAMS.db entrée: archive.500 entrée: axinstall.log entrée: emacsEMFYx6 entrée: fvwmrcTPYp4h => #unspecifiedLa fonction
port-seekpermet de positionner le pointeur de fichier sur le numéro de l'entrée du répertoire correspondante, à partir de zéro. La fonctionport-tellretourne le numéro de l'entrée courante.
Informations sur les fichiers d'un répertoire
Lorsque qu'un répertoire est ouvert, il est pratique de pouvoir obtenir des informations sur les fichiers qu'il contient. Pour cela, nous disposons de la fonction suivante :
(port-stat nom [répertoire])Cette fonction retourne un vecteur contenant les informations relatives au fichier nommé
nomdu répertoire spécifié. Si aucun répertoire n'est spécifié, le fichier d'entrée standard est utilisé. Si une erreur se produit#fest la valeur de retour.Le vecteur retourné contient les éléments suivants :
#tsinomdésigne un répertoire,#fsinon.
#tsinomdésigne un fichier régulier,#fsinon.
#tsinomdésigne un lien,#fsinon.
- Une chaîne de caractères représentant les droits sur le fichiers, selon le format Unix.
- La taille du fichier
nom.
- Date de dernière modification du fichier, sous la forme d'un réel. Ce réel peut être manipulé avec les fonctions
date->stringetdate->vector
- Date de création du fichier, sous la forme d'un réel.
- Date de dernier accès du fichier, sous la forme d'un réel.
Port en lecture ET écriture
Par défaut, le langage Scheme permet d'ouvrir des fichiers en lecture ou en écriture.Lorsque le fichier est ouvert en écriture alors qu'il existe déjà, le contenu précédant est perdu et la taille du fichier est fixée à zéro.
L'environnement OpenScheme permet d'ouvrir des ports en lecture et écriture. Si le fichier existe, son contenu n'est pas perdu. Cependant, il sera écrasé si le pointeur de fichier n'est pas positionné à la fin de celui-ci. Les fonctions relatives à ces ports sont
open-input-output-file,open-input-output-stringetclose-input-output-port.De plus, les ports peuvent être ouverts en écriture de manière à ce que le contenu précédent ne soit pas altéré. Ces ports sont ouverts et fermés avec les fonctions
open-append-file,close-append-port,call-with-append-fileetwith-append-to-file.
Connexion réseau
Les communications inter machines utilisent souvent les ports au sens de Unix ; l'objet ouvert est souvent connu sous le nom de socket. L'utilisation des sockets est maintenant disponibles sous d'autres environnement que Unix, comme des machines Windows ou Macintoch.
L'environnement OpenScheme permet ouvrir des ports distants et d'y accéder avec les fonctions d'entrées / sorties standards.
Pour ouvrir un socket, on utilise les fonctions standard d'ouverture de fichier, comme
open-input-porten précisant le nom du fichier de la manière suivante (il est possible d'utiliser les fonctions d'ouverture standards ; cependant, les sockets permettent un accès bidirectionnel) :socket://machine:portLes fonctions pour manipuler le pointeur de fichier sont inactives sur ce type de port. Les fonctions de lecture/écriture en mode caractères sont utilisables comme si le socket était un fichier local.
Connexions FTP/HTTP
Les protocoles FTP (File Transfert Protocol) et HTTP (Hyper Text Transfert Protocol) sont très utilisés pour transférer des fichiers depuis ou vers un hôte distant. OpenScheme permet d'accéder à ces protocoles en utilisant les fonctions standards d'ouverture de fichiers. Pour cela, le fichier est spécifié de la manière suivante :
ftp://[utilisateur[:pass]@]hôte/fichierou
http://[utilisateur[:pass]@]hôte/fichierLe nom d'utilisateur et le mot de passe sont optionnels. Le fichier peut spécifié soit un fichier ouvert en lecture soit en écriture. Les fonctions manipulant le pointeur de fichier sont actives.
Si
fichierspécifie un répertoire distant, le nom des entrées du répertoire sont accessibles comme en mode local.
Exemple
Dans cet exemple, nous utilisons les ports sockets pour nous connecter à un serveur de mail POP afin de savoir si nous avons des mails disponibles.
Le protocole POP est très simple. Voici à la main, comment nous pouvons connaître le nombre de mail en attente.
Supposons que votre serveur de mail soit pop.serveur.fr et votre nom de login pour le mail soit cmoi et votre mot de passe mdp. Avec telnet, nous ouvrons le port 110 du serveur POP comme suit :
$ telnet pop.serveur.fr 110 Trying 192.101.21.253... Connected to pop.serveur.fr. Escape character is '^]'. +OK POP3 pop.serveur.fr v5.12 server ready USER cmoi +OK User name accepted, password please PASS mdp +OK Mailbox open, 1 messages LIST +OK Mailbox scan listing follows 1 7503 . QUIT +OK Sayonara Connection closed by foreign host. $Nous commençons par nous identifier avec les commandes USER et PASS ; le nombre des messages est indiqués par le serveur. Avec la commande LISTE, nous obtenons la liste des messages ; lorsqu'il n'y a plus de message, un point est affiché. Enfin, la commande QUIT termine la session avec le serveur.
Tout cela est très simple, et nous allons programmer cela en OpenScheme !
#! /usr/local/bin/osm --banner=off --exec (define (mail? server user pass) (let* (; port du serveur POP [port 110] ; adresse à ouvrir [url (format #f "socket://~a:~a" server port)] ; le port lié à la socket [port (open-input-output-file url)] ; port pour le debug: ; #t écran, ; #f pas de message [debug #t]) (if port (begin ; lire l'invite du serveur (format debug "~a\n" (read-line port)) ; envoyer le nom d'utilisateur (format port "USER ~a\r\n" user) ; lire le résultat (format debug "~a\n" (read-line port)) ; envoyer le mot de passe (format port "PASS ~a\r\n" pass) ; lire le résultat (format debug "~a\n" (read-line port)) ; demander la liste des messages (display "LIST\r\n" port) ; lire le résultat (format debug "~a\n" (read-line port)) ; lire la liste des messages (let ([n (let loop () (let ([l (read-line port)]) (format debug "~a\n" l) (if (or (eof-object? l) ; si c'est un point ; terminer (eqv? l ".")) 0 ; ajouter un et continuer (+ 1 (loop)))))]) ; terminer la session (display "QUIT\r\n" port) ; lire le résultat (format debug "~a\n" (read-line port)) ; fermer le port (close-input-output-port port) ; retourner la valeur n)) (error "Incapable d'ouvrir l'URL ~a" url)))) ; programme principal (let ([n (mail? "pop.serveur.fr" "cmoi" "mdp")]) (format #t "Vous avez ~a mail~a en attente\n" n (if (> n 1) "s" "")))Le lecteur pourra s'il le désire consulter les RFC (Request For Comments) concernant le protocole POP et réaliser un client POP complet avec réception et émission de mail.
![]()
![]()
![]()
![]()
![]()
Next: Recherche dans une liste Up: Premier programmes Previous: Entées / sorties   Contents   Index © 1993 to 2001 Erian Concept