/******************************************************************* 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 */