/*******************************************************************
Interfaces d'Entre'es/Sorties Le-Lisp V15.2
utilisable sur tous les UNIX.
*****************************************************************
Ce fichier est en lecture seule hors du projet ALE de l'INRIA
Il est maintenu par : ILOG S.A. 9 rue Royale, 75008 Paris, France
*****************************************************************
$Header: llstdio.c,v 4.10 89/01/09 12:48:03 neidl Exp $
*******************************************************************/
/* liste des conditionnelles :
MAXCHAR
MAXCHAN
S5
BSD4x
BSD4.2
IBMRT
INRIA
FOREIGN
/*****************************************************
Parame`tres du syste`me multi-fichiers
******************************************************/
#ifndef MAXCHAR
#define MAXCHAR 256 /* taille d'un tampon LLM3 */
#endif MAXCHAR
#ifndef MAXCHAN
#define MAXCHAN 12 /* nombre de canaux disponibles */
#endif MAXCHAN
#include <stdio.h>
#include <errno.h>
#ifdef S5
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#endif S5
#ifdef BSD42
#include <sys/time.h>
#include <signal.h>
#endif BSD42
#ifndef IBMRT
#include <sgtty.h>
#endif IBMRT
extern int errno;
/* le nombre de canaux disponibles */
extern int maxchan;
/********************************************************
L'impression des erreurs d'E/S
*********************************************************/
/* L'indicateur controlant l'impression des erreurs syste`me
(de'fini dans lelisp.c) */
extern int **prtmsgs;
#define errreturn(M,V) { \
if (**prtmsgs != 0) { \
perror(M); \
write(2, "\r", 1); \
} \
return(V); \
}
/* retour des codes d'erreur */
#define codereturn(v) { \
if (v) \
errreturn("Le←Lisp",1); \
return(0); \
}
/********************************************************
La fonction d'initialisation des d'E/S
*********************************************************/
/* llstdio: initialisation du syste`me multi-fichier
------------------------------------------------- */
llstdio () {
maxchan = MAXCHAN;
}
/********************************************************
Les fonctions utilisant le terminal
*********************************************************/
/* ttyin: lecture d'un caracte`re
------------------------------ */
char caractere;
char ttyin () {
#ifdef INRIA
/*
BSD4.2 pose un proble`me particulier, car il restarte
les I/O interrompues, on fait donc une attente a` l'aide
d'un select qui surveille stdin et termine sur un signal
ou sur l'arrive'e d'un caracte`re.
Malheureusement, il y a beaucoup de bugs dans les vieux
noyaux BSD 4.2 :
- le ↑Z pendant un select peut tuer le processus.
- les pseudo-ttys esclaves ne sont pas reveille'es
pendant un select.
*/
int readfds = 1;
char buf;
extern char ttys();
if (select(1,&readfds,0,0,0) < 0) /* interompu ? */
return(-1); /* retour Lelisp */
#endif INRIA
switch (read(0,&caractere,1)) { /* le resultat du read */
case 0 : out(0); /* EOF, on quitte Lelisp */
case 1 : return(caractere);}; /* 1 caracter, on le rend */
return((char) -1); /* erreur, retour Lelisp */
}
/* ttys: test de la frappe d'un caracte`re
--------------------------------------- */
char ttys (buffer)
char *buffer;
{
int nchars;
#ifdef BSD4x
retry:
if (ioctl(0, FIONREAD, &nchars) == -1)
if (errno == EINTR)
goto retry;
else if (errno == EBADF) {
fprintf(stderr,
#ifdef FOREIGN
"\r\nLe-Lisp : standard input is closed !\r\n");
#else FOREIGN
"\r\nLe-Lisp : l'entree standard est fermee !\r\n");
#endif FOREIGN
out(-1);
} else
return(-1);
#endif BSD4x
#ifdef S5
int vfcntl;
vfcntl = fcntl (0, F←GETFL, nchars);
vfcntl |= O←NDELAY;
vfcntl = fcntl (0, F←SETFL, vfcntl);
nchars = read (0, buffer, 1);
if (nchars <= 0)
nchars = -1;
else
nchars = 0;
vfcntl &= ~O←NDELAY;
vfcntl = fcntl (0, F←SETFL, vfcntl);
return (nchars);
#endif S5
if(nchars == 0) return(-1);
for (errno=EINTR; errno==EINTR;){ /* system call interupted */
switch (read(0,buffer,1)) { /* le resultat du read */
/* case 0 : out(0); en prevision du tys+eof SYS5 */
case 1 : return(0);};} /* 1 caractere lu, retour Lelisp */
return(-1); /* autre erreur que EINTR */
}
/* ttyinstr: lecture d'une ligne directement par le syste`me
--------------------------------------------------------- */
int ttyinstr (buffer, maxlen)
char *buffer;
int maxlen;
{
int n, c;
for (n = 0; n < maxlen; n++) {
c = ttyin();
if ((c == '\r') || (c == '\n'))
return(n);
*(buffer + n) = c;
}
return(maxlen);
}
/* ttyout: impression d'une chai↑ne de caracte`res
----------------------------------------------- */
ttyout (length, buffer)
int length;
char *buffer;
{
int cc, count;
for (count = 0; count != length; count += cc) {
cc = write (1, buffer+count, length-count);
if (cc < 0)
break;
}
}
/* ttycrlf: impression de CR/LF
---------------------------- */
ttycrlf () {
ttyout (2, "\r\n");
}
/********************************************************
Les fonctions utilisant les fichiers
*********************************************************/
/* les tampons d'entre'e */
struct {
char contents[MAXCHAR];
char *position;
char *last;
int filedesc;
} channels[MAXCHAN];
/* inbf: lecture d'une ligne sur un fichier texte
----------------------------------------------
Lit la ligne suivante sur le canal argument.
La taille de la ligne lue est rendue dans *ptaille.
Retourne un code condition:
0: Ok on a une une ligne comple`te
1: On a rien lu a` cause de EOF
2: On a lu un de'but de ligne qui de'passe MAXCHAR
3: On a lu la dernie`re ligne du fichier qui ne se termine
pas par CR/LF
*/
int inbf (canal, buffer, ptaille)
int canal;
char *buffer;
int *ptaille;
{
int resread;
char *ficbuff;
char *ficpos;
char *ficlast;
int ncars;
ncars = 0;
again:
ficpos = channels[canal].position;
ficlast = channels[canal].last;
while ((ncars < MAXCHAR) &&
(ficpos != ficlast) &&
((*buffer++ = *ficpos++) != '\n')) {
ncars += 1;
}
if (*(buffer - 1) == '\n') {
channels[canal].position = ficpos;
*ptaille = ncars;
return(0);
}
if (ncars == MAXCHAR) {
channels[canal].position = ficpos;
*ptaille = ncars;
return(2);
}
ficbuff = channels[canal].contents;
resread = read (channels[canal].filedesc, ficbuff, MAXCHAR);
if (resread <= 0) {
channels[canal].position = channels[canal].contents;
channels[canal].last = channels[canal].contents;
if (ncars > 0) {
*ptaille = ncars;
return(2);
} else {
*ptaille = 0;
return(1);
}
}
channels[canal].last = ficbuff + resread;
channels[canal].position = ficbuff;
goto again;
}
/* inbfb: lecture d'un tampon sur un fichier binaire
-------------------------------------------------
code condition:
0: EOF
1: Ok
*/
int inbfb (canal, buffer, ptaille)
int canal;
char *buffer;
int *ptaille;
{
int cc;
cc = read (channels[canal].filedesc, buffer, MAXCHAR);
if (cc > 0) {
*ptaille = cc;
return(0);
} else {
*ptaille = 0;
return(1);
}
}
/* inb: lecture d'un nb arbitraire de caracte`res sur un fichier binaire
---------------------------------------------------------------------
code condition:
0: EOF
1: Ok
*/
int inb (canal, buffer, length, ptaille)
int canal;
char *buffer;
int *ptaille;
{
int cc;
cc = read (channels[canal].filedesc, buffer, length);
if (cc > 0) {
*ptaille = cc;
return(0);
} else {
*ptaille = 0;
return(1);
}
}
/* outf: imprime une ligne sur un fichier texte
-------------------------------------------- */
int outf (canal, length, buff)
int canal;
int length;
char *buff;
{
if (write (channels[canal].filedesc, buff, length) != length)
errreturn ("Le←Lisp : outf1 ", 1);
if (write (channels[canal].filedesc, "\n", 1) != 1)
errreturn ("Le←Lisp : outf2 ", 1);
return(0);
}
/* outfl: imprime une ligne sans marque de fin de ligne sur un fichier texte
------------------------------------------------------------------------- */
int outfl (canal, length, buff)
int canal;
int length;
char *buff;
{
if (write (channels[canal].filedesc, buff, length) != length)
errreturn ("Le←Lisp : outfl ", 1);
return(0);
}
/* llseek: positionnement du canal <chan> a` la position <n1>*<n2>
------------------------------------------------------------------
(uniquement pour des defexterns) */
int llseek (canal, n1, n2)
int canal, n1, n2;
{
if (lseek (channels[canal].filedesc, n1*n2) != -1)
errreturn ("Le←Lisp : llseek ", 1);
return(0);
}
/* infile: ouverture d'un fichier en lecture
----------------------------------------- */
int infile (canal, buff)
int canal;
char *buff;
{
if ((channels[canal].filedesc = open(buff, 0)) != -1) {
channels[canal].position = channels[canal].contents;
channels[canal].last = channels[canal].contents;
return(0);
}
errreturn(buff, 1);
}
/* infile: ouverture d'un fichier en e'criture
------------------------------------------- */
int oufile (canal, buff)
int canal;
char *buff;
{
int fd;
fd = creat (buff, 0666); /* rw-rw-rw | umask */
if ((channels[canal].filedesc = fd) != -1) {
channels[canal].position = channels[canal].contents;
channels[canal].last = channels[canal].contents;
return(0);
}
errreturn(buff, 1);
}
/* apfile: ouverture d'une fichier en ajout
---------------------------------------- */
int apfile (canal, buff)
int canal;
char *buff;
{
int fd;
if ((fd = open (buff, 1)) == -1)
fd = creat (buff, 0666); /* rw-rw-rw | umask */
lseek (fd, 0, 2);
if ((channels[canal].filedesc = fd) != -1){
channels[canal].position = channels[canal].contents;
channels[canal].last = channels[canal].contents;
return(0);
}
errreturn(buff, 1);
}
/* fclos: fermeture d'un fichier
----------------------------- */
int fclos (canal)
int canal;
{
codereturn (close (channels[canal].filedesc));
}
/* fdele: de'truit un fichier
--------------------------
retourne le code condition de C */
int fdele (buff)
char *buff;
{
codereturn (unlink (buff));
}
/* frena: change le nom d'un fichier
---------------------------------
retourne le code condition de C */
int frena (nom1, nom2)
char *nom1, *nom2;
{
#ifdef BSD42
if (rename(nom1, nom2) == -1)
errreturn("Le←Lisp : rename ", 1);
#else BSD42
if (close (open(nom1,0)) == 0) {
unlink(nom2);
if (link(nom1, nom2) == 0)
if (unlink(nom1) == 0)
return(0);
errreturn(nom1, 1);
} else
errreturn(nom1, 1);
#endif BSD42
}
/* fprobe: teste l'existence d'un fichier
--------------------------------------
retourne le code condition de C */
int fprobe (buff)
char *buff;
{
int fd;
fd = open(buff, 0);
if (fd != -1)
codereturn (close (fd)) /* pas de ; */
else
return(fd);
}
int llgetchan(a) /* channel LL --> FD C */
int a;{ /* un canal Lelisp */
return(channels[a].filedesc);}; /* le file descriptor C */
int llsetchan(a,b) /* FD C --> channel LL */
int a,b;{ /* canal LL, FD C */
channels[a].filedesc=b; /* remplacer l'ancien FD ... */
return(b);}; /* ... par le nouveau FD C */