À rendre pour le lundi 6 mars, 18h00. |
Ce DM est facultatif et portera sur les processus et la communication entre processus. En voici une version partielle n'utilisant que les parties du cours déjà vues.
Confutils
et d'un script illustrant l'usage de cette bibliothèque.
L'écriture de la bibliothèque constitue la partie la plus importante du
travail. Elle peut se décomposer elle-même en des fonctions d'usage général
telles que l'exécution d'une commande avec redirection, l'exécution de
commandes en pipeline, etc. et des fonctions plus spécifiques comme la
recherche de l'existence d'une commande dans un chemin d'exécution.Misc
du
cours.
PATH
. list_of_path
qui traduit une chaîne au format UNIX,
i.e. dans laquelle les chemins sont représentés séparés par le caractère ':',
vers
une liste de chemins. Écrire la fonction inverse path_of_list
—on devra
produire une erreur si l'un des chemins contient le caractère ':' car cela
donnerai au résultat une interprétation incorrecte. Écrire également une
fonction get_path
qui récupère la variable d'environnement PATH
comme une
liste de chemins. (On pourra si besoin utiliser la bibliothèque Str
.)
val list_of_path : string -> string list val path_of_list : string list -> string val get_path : unit -> string list |
find_in_path
qui prend un prédicat de type
string -> bool
, une liste de chemins, un fichier et retourne la liste
des chemins combinés avec le fichier qui satisfont le prédicat.
val find_in_path : (string -> bool) -> string list -> string -> string list |
access
pour pouvoir tester également le
type et les dates de modifications des fichiers. On souhaite pouvoir
effectuer les test suivants:
type filetest = | Fexists (* file exists *) | Freadable (* file exists and is readable *) | Fwritable (* file exists and is writable *) | Fexecutable (* file exists and is executable *) | Fdir (* file exists and is a directory *) | Freg (* file exists and is a regular file *) | Flnk (* file exists and is a symbolic link *) | Fnonempty (* file exists and is non empty *) | Fnewer of string (* files exists and is newer than this other file *) | Folder of string (* files exists and is older than this other file *) | Fequal of string (* files is identical (same st_ino and st_dev) to this other file *) |
testfile
qui prend une liste d'éléments de
type filetest
et retourne un booléen indiquant si le fichier satisfait
tous les tests. Si la liste est vide, on se contentera de tester Fexists
.testfile
attrape donc les exceptions qui déterminent la réponse
au calcul demandé, mais elle devra laisser passer les autres qui indiquent
une erreur pendant ce calcul (par exemple une erreur d'entrée-sortie,
l'absence de mémoire suffisante). On indiquera les exceptions qui peuvent
être retournées.
val testfile : filetest list -> string -> bool |
string_of_file
et file_of_string
qui lisent un
fichier dans une chaîne de caractères et écrivent une chaîne de caractères
dans un fichier. string_from_descr
and descr_from_string
qui font la même chose mais dans
des descripteurs de fichiers. On veut que ces fonctions puissent être
utilisées dans un contexte assez large, en particulier en présence de
signaux et pour des descripteurs de fichiers variés.
Ces fonctions pourront lever les mêmes exceptions que les appels système
read
et write
sauf EINTR
. Le descripteur passé à ces fonctions
est supposé ouvert à l'appel et laissé ouvert en sortie.
val string_from_descr : Unix.file_descr -> string val descr_from_string : string -> Unix.file_descr -> unit |
string_of_file
and file_of_string
(on
donnera les droits 0o640
aux fichiers créés) et on écrasera
le fichier s'il existe déjà.
val string_of_file : string -> string val file_of_string : string -> string -> unit |
execvp_to_list
qui prend une commande cmd
et un tableau d'argument argv
, et lance la commande avec ses arguments
(en ajoutant la commande elle-même comme premier argument) dans un autre
processus et recueille le résultat (sortie standard) de l'exécution
dans une liste de chaîne de caractères (une par ligne sans le '\n'
final). La fonction devra se comporter comme la fonction system
vis à vis
de la protection des signaux pendant l'exécution de la commande.
val execvp_to_list : string -> string array -> string list |
execvp_redirect
qui prend en argument une liste de
redirections à effectuer, une commande, un tableau d'arguments et exécute
la commande dans un nouveau processus après avoir effectué les redirections
demandées. Ici, on ne changera pas le comportement vis-à-vis des signaux
pendant l'exécution. type redirection = In_from_file of string (* < file *) | Out_to_file of string (* > file *) | Err_to_file of string (* 2> file *) | Out_append_to_file of string (* >> file *) | Err_to_out (* 2>&1 *) | In_from_string of string (* <<END *) | Err_null (* >/dev/null *) | Out_null (* 2>/dev/null *) | Silent (* >/dev/null 2>&1 *) val execvp_redirect : redirection list -> string -> string array -> Unix.process_status |
Unix_error
serait levée sans bonne raison. On fera
également attention à ce qu'elles effacent systématiquement les fichiers
temporaires créés.ocaml_output
qui prend une liste de substitutions et
une liste de paires de fichiers (fichier d'origine, et fichier généré), et
effectue les substitutions. Les substitutions sont des paires de chaînes,
la première étant celle devant être remplacée, la seconde celle la
remplaçant. On pourra utiliser la fonction Str.global_replace
après avoir
appliqué la fonction Str.regexp
sur chaque chaîne à remplacer.
val ocaml_output : (string * string) list -> (string * string) list -> unit |
ocaml_prog
, qui teste si un programme existe dans
le chemin spécifié par la variable PATH
et s'il est exécutable, avant
de retourner le nom complet du fichier trouvé.
val ocaml_prog : string -> string |
ocaml_defined
, qui teste si une valeur Ocaml
(List.map
par exemple) est définie, i.e. si un petit programme
contenant cette valeur peut être compilé par ocamlc -c
.
val ocaml_defined : string -> bool |
ocaml_value_has_type
, qui teste si une valeur Ocaml
est définie avec le type spécifié. On pourra utiliser le fait que l'expression
(x : t)
vérifie que x
a le type t
avant de retourner la valeur de
x
.
val ocaml_value_has_type : string -> string -> bool |
ocaml_version
, qui prend en argument le nom du
fichier exécutable correspondant à ocamlc
, et retourne la version
d'Ocaml, c'est-à-dire la première ligne de la sortie de ocamlc -v
.
val ocaml_version : string -> string |
open Unix;; open Confutils;; open Printf;; let ocamlrun = ocaml_prog "ocamlrun" let ocamlc = ocaml_prog "ocamlc" let ocaml_version = ocaml_version ocamlc let _ = printf "OCAMLC=%s\nOCAMLRUN=%s\nOCAMLVERSION=%s\n%!" ocamlrun ocamlc ocaml_version let _ = let check v = Printf.printf "%s %s\n" v (if ocaml_defined v then "defined" else "is not defined") in check "succ"; check "scuc"; let check v t = Printf.printf "%s %s %s\n" v (if ocaml_value_has_type v t then "is:" else "is not:") t in check "succ" "int -> int"; check "succ" "int -> bool";; let _ = ocaml_output [ "@CONFIG_OCAMLC@", ocamlc; "@CONFIG_OCAMLRUN@", ocamlrun; "@CONFIG_OCAMLVERSION@", ocaml_version; ] [ "Makefile.config.in", "Makefile.config"] |
Makefile.config.in
a le contenu suivant:
OCAMLC=@CONFIG_OCAMLC@ OCAMLRUN=@CONFIG_OCAMLRUN@ OCAMLVERSION=@CONFIG_OCAMLVERSION@ configure: misc.ml confutils.ml configure.ml $(OCAMLRUN) $(OCAMLC) -c misc.ml $(OCAMLRUN) $(OCAMLC) -c confutils.ml $(OCAMLRUN) $(OCAMLC) -c configure.ml $(OCAMLRUN) $(OCAMLC) -o configure str.cma unix.cma misc.cmo \ confutils.cmo configure.cmo |
Makefile.config
après exécution du
script.
Ce document a été traduit de LATEX par HEVEA