/******************************************************************* Le-Lisp (r) version 15.22 Bibliothe`que d'Exe'cution en C utilisable sur syste`me d`exploitation "a` la UN*X" ***************************************************************** (r) Le-Lisp est une marque de'pose'e de l'INRIA ***************************************************************** Ce fichier est en lecture seule. Il est maintenu par : ILOG S.A. 2 Avenue Gallie'ni BP 85 94253 Gentilly Cedex ***************************************************************** $Header: lelisp.c,v 4.43 89/01/16 19:53:14 kuczynsk Exp $ *******************************************************************/ /* Liste des conditionnelles de compilation C : ============================================ Les types et sous-types de syste`mes UNIX : S5 : System V SPS9 : sous-type Ridge SPS9 SPS7 : sous-type SPS7 SMX 5.1 CADMUS : sous-type Cadmus HP9300 : sous-type HP9000 se'rie 300 LEWS : enleve les ← devant les defextern UNIGRAPH : enleve les ← devant les defextern IBMRT : BSD4x : Syste`me Berkeley BSD41 : de type 4.1 BSD42 : de type 4.2 SEQUENT : sous-type Sequent DYNIX Les traits pre'sents : FOREIGN : les messages sont en Breton! PAGESIZE: La taille des pages EXECORE : L'image me'moire est un exe'cutable (a.out) Les autres options fournies a` la compilation C NBSYST : nume'ro du syste`me a` cre'er FILEINI : nom du fichier startup FILIT : indicateur de fichier initial LLBAN : indicateur de pre'sence de bannie`re PAGESIZE : la taille d'une page me'moire TIMEUNIT : fre'quence de l'horloge. LELISPDIR : repertoire du systeme lelisp */ /* Choix du numero du systeme : ---------------------------- 1 = VERSADOS, 2 = VME, 3 = MicroMega, 4 = APOLLO 5 = SM90, 6 = PE32OS, 7 = PE32UNIX, 8 = VAXUNIX 9 = VAXVMS, 10= multics, 11= METHEUS, 12= UNIVERSE68 13= MCPM86, 14= PCDOS, 15= MACII, 16= VAXIS3, 17= MAC, 18= SPS9, 19= BELLMAC, 20= VM370UTS, 21= PCS, 22= SUN, 23= HP9000-300, 24= METAVISEUR, 25= GOULD, 26= IBMRT, 27= PYRAMID, 28= SEQUENT 29= UNIGRAPH, 30= CL1000, 31= CL1020, 32= TEKTRONIX 43xx, 33= C, 34= DPX1000, 35= SUN4 36= ATARI, 37= CONVEX. */ #ifndef NBSYST #define NBSYST 22 #endif NBSYST /* Les autres parametres dependants du systeme ------------------------------------------- */ #ifndef FILEINI #define FILEINI "/usr/ilog/lelisp/llib/startup.ll" #endif FILEINI #define FILIT 0 /* 0 = fichier initial, 1 = core */ #define LLBAN 0 /* 0 = banniere, 1 = silence */ /* la taille des pages (obtenu par pagesize(1) ou getpagesize(2) ou par la documentation). Doit etre une puissance de 2 >= BIPTR */ #ifndef PAGESIZE #define PAGESIZE 1024 #endif PAGESIZE #define align(x) (x = ((x+PAGESIZE-1)&~(PAGESIZE-1))) /* Les tailles des zones (attention aux Unite's!) --------------------------------------------- */ /* Les Unites avec lesquelles sont definies les zones */ #define PTR (sizeof (char *)) #define BIPTR (PTR*2) #define KPTR (PTR*1024) int SSTACK = 6; /* en K objets de type pointeurs */ int SCODE = 128; /* en K octets */ int SHEAP = 70; /* en K octets */ int SNUMB = 0; /* en K objets de type entiers */ int SFLOAT = 1; /* en K objets de type flottant */ int SVECT = 1; /* en K objets de type vecteur */ int SSTRG = 3; /* en K objets de type chaine */ int SSYMB = 2; /* en K objets de type symboles */ int SCONS = 3; /* en 8 K CONS */ int UCONS = 0; /* en 32 CONS */ /* Si en mode debug, on n'arme pas les interruptions et on ne fait pas de stty. Principalement pour adb. */ int lldebug=0; /* les include */ #include <sys/types.h> /* pour tout le monde */ #include <sys/stat.h> /* pour tout le monde */ #include <signal.h> /* pour les signaux */ #include <stdio.h> /* pour les entre'es sorties */ #include <errno.h> /* pour perror(), et le save-core BSD */ #include <a.out.h> /* pour getglobal, et le save-core BSD */ /* V-- cf page 3-218 AIX o/s guide */ #if IBMRT || LEWS || UNIGRAPH #undef n←name #endif /* IBMRT LEWS UNIGRAPH */ #ifdef LEWS /* Les bibliotheques du LEWS exploitent ces traits */ #define u3b 0 #define vax 0 #define u3b5 0 #define sm90 1 /* pour nlist (dans a.out.h) */ #define ridge 0 #endif LEWS #ifdef BSD42 /* pour runtime */ #include <sys/time.h> #include <sys/resource.h> #else BSD42 #include <time.h> #ifdef Perkin /* le Perkin n'a pas l'include sys/times.h */ struct tms { long tms←utime; long proc←system←time; long child←user←time; long child←system←time; }; #else Perkin #include <sys/times.h> /* pour les autres */ #endif Perkin #endif BSD42 #ifdef VAXUNIX #define N←DATADDR(gg) gg.a←text #endif VAXUNIX /* les point d'entree de Le-Lisp LLM3 */ extern host←start(), llstdio(); extern float accusingle1; /* Les variables globales Le-Lisp. Elles sont toutes definies dans LLINIT.LLM3 mais doivent etre chargees ici. */ /* la pile d'evaluation de Le-Lisp */ extern char *bstack, *estack, *mstack1, *mstack2; /* les limites des zones des differents types Le-Lisp */ extern char *bcode, *ccode, *ecode, *bheap, *cheap, *eheap, *bnumb, *cnumb, *bfloat, *cfloat, *bvect, *cvect, *bstrg, *cstrg, *bsymb, *csymb, *bcons, *ccons, *econs; char *llucode, *lluheap; /* fin des zones code et heap (trous) */ /* le fichier initial et la ligne de commande */ extern int filiz, filit; extern char *filin; extern int llban; /* le numero (type) du systeme Le-Lisp */ extern int nbsyst; /* Le flag controlant l'impression des erreurs syste`me */ extern int **prtmsgs; /* il est dans le save-core ! */ #define errreturn(M,V) { if(**prtmsgs != 0) perror(M) ; return(V); } /* Les variables du lanceur Elles ne sont pas sauve'es par save-core */ /* tailles des zones */ int sstack, scode, sheap, snumb, sfloat, svect, sstrg, ssymb, scons; /* bits invisibles */ int stbin; char *btbin; /* bits du GC */ int stbgc; char *btbgc; /* debut et fin de la memoire */ char *bmem; char *emem; #ifdef EXECORE /* Environnement Shell initial (pour le restore-core BSD) */ char **envpini; #endif EXECORE /* Path absolu du repertoire lelisp */ char *lelisp←racine; /* Path absolu du binaire lelispbin */ char lelispbin[256]; char *getenv(); /* les variables et fonctions du cload */ char *mktemp(); char template[] = "/tmp/lelisp←XXXXXX"; /* Points d'entree */ /* Pour les erreurs */ int out(), oupps(); char *usage(); /* References externes */ /* Allocation de la me'moire */ extern char *brk(); extern char *sbrk(); #define RATE (char *) -1 char *END; /******************************************************** Gestion du Terminal ********************************************************/ #ifdef S5 #include <fcntl.h> #include <termio.h> #endif S5 #ifdef BSD4x #include <sgtty.h> #endif BSD4x #ifdef S5 struct termio tioini, tiolisp; /* les termio initiaux et lisp */ #endif S5 #ifdef BSD4x struct sgttyb ttyini, ttylisp; /* les stty initiaux et lisp */ #endif BSD4x int realterminal = 0; /* =0 c'est un vrai terminal */ extern init←stty(); extern lisp←stty(); extern unix←stty(); /* init←stty: intialise les structures stty initiales -------------------------------------------------- */ init←stty () { realterminal = isatty(0); /* est-on interactif ? */ if (realterminal != 0) { #ifdef S5 (void) ioctl(0, TCGETA, &tioini); /* prend le tty initial */ (void) ioctl(0, TCGETA, &tiolisp); tiolisp.c←cc[VMIN] = 6; tiolisp.c←cc[VTIME] = 1; tiolisp.c←iflag &= ~(IGNBRK|INLCR|ICRNL); tiolisp.c←iflag |= BRKINT; tiolisp.c←oflag &= ~(OPOST|ONLCR|OCRNL|ONOCR|ONLRET); tiolisp.c←lflag &= ~(ICANON|ECHO|ECHOE|ECHOK|ECHONL|NOFLSH); tiolisp.c←lflag |= ISIG; (void) ioctl(0, TCSETAF, &tiolisp); /* mets le tty lisp */ #endif S5 #ifdef BSD4x (void) gtty(0, &ttyini); /* prend le tty initial */ (void) gtty(0, &ttylisp); /* recopie' dans le tty lisp */ ttylisp.sg←flags |= CBREAK; /* Lisp est en cbreak -echo -nl */ ttylisp.sg←flags &= ~(ECHO|CRMOD); #endif BSD4x } } /* lisp←stty: passe le terminal en mode Le-Lisp -------------------------------------------- */ lisp←stty () { if (realterminal != 0) #ifdef S5 (void) ioctl(0, TCSETAF, &tiolisp); #endif S5 #ifdef BSD4x (void) stty(0, &ttylisp); #endif BSD4x } /* unix←stty: passe le terminal en mode UN*X ----------------------------------------- */ unix←stty () { if (realterminal != 0) #ifdef S5 (void) ioctl(0, TCSETAF, &tioini); #endif S5 #ifdef BSD4x (void) stty(0, &ttyini); #endif BSD4x } /******************************************************** Gestion de la Signalerie UN*X ********************************************************/ extern ll←break(); /* dans ../<system>/ll<system>.llm3 */ extern ll←merro(); extern ll←clock(); #ifdef BSD41 onstop41(signo) /* gestion du "stopped job" ↑Z sous BSD 4.1 */ int signo; { unix←stty(); sigset(signo, SIG←DFL); kill(0, signo); sigset(signo, onstop41); } oncont41(signo) /* repasse en Lisp */ int signo; { lisp←stty(); } #endif BSD41 #ifdef BSD42 onstop42(signo) /* gestion du "stopped job" ↑Z sous BSD 4.2 */ int signo; { unix←stty(); signal(SIGTSTP, SIG←DFL); killpg(getpgrp(0), signo); } oncont42(signo) /* repasse en mode Lisp */ int signo; { lisp←stty(); signal(SIGTSTP, onstop42); } shstop42(signo) /* pendant un COMLINE */ int signo; { signal(SIGTSTP, SIG←DFL); killpg(getpgrp(0), signo); } shcont42(signo) /* pendant un COMLINE */ int signo; { signal(SIGTSTP, shstop42); } #endif BSD42 /* init←signal: intialise les signaux UN*X ge're's par Le-Lisp ----------------------------------------------------------- */ init←signal() { int i; if ( lldebug == 0 ) { for(i = 3 ; i <= 12; signal(i++, oupps)); #ifdef BSD41 sigset(SIGTSTP, onstop41); sigset(SIGCONT, oncont41); #endif BSD41 #ifdef BSD42 signal(SIGTSTP, onstop42); signal(SIGCONT, oncont42); #endif BSD42 } } /* pour e'viter un "core-dumped" pour les mauvais signaux */ oupps(n) { #ifdef FOREIGN fprintf(stderr, "Le-Lisp : I quit on signal %d\r\n", n); #else FOREIGN fprintf(stderr, "signal %d\r\n", n); fprintf(stderr, "OUPPS! J'ai failli faire un core\r\n"); #endif FOREIGN out(-1); } int←ign () { if (realterminal != 0) signal(SIGINT, SIG←IGN); /* interrupt */ signal(SIGILL, SIG←IGN); /* illegal instruction */ signal(SIGBUS, SIG←IGN); /* bus error */ signal(SIGSEGV, SIG←IGN); /* segmentation violation */ signal(SIGTRAP, SIG←IGN); /* trace trap */ signal(SIGFPE, SIG←IGN); /* floating point exception */ #ifdef BSD42 signal(SIGTSTP, shstop42); /* stop generated from keyboard */ signal(SIGCONT, shcont42); /* continue after stop */ #endif }; /* int←std: passe en mode signaux standard pour le COMLINE ------------------------------------------------------- */ int←std() { if (realterminal != 0) signal(SIGINT, SIG←DFL); /* interrupt */ signal(SIGILL, SIG←DFL); /* illegal instruction */ signal(SIGBUS, SIG←DFL); /* bus error */ signal(SIGSEGV, SIG←DFL); /* segmentation violation */ signal(SIGTRAP, SIG←DFL); /* trace trap */ signal(SIGFPE, SIG←DFL); /* floating point exception */ #ifdef BSD42 signal(SIGTSTP, SIG←DFL); /* stop generated from keyboard */ signal(SIGCONT, SIG←DFL); /* continue after stop */ #endif }; /* inton: arme les signaux UN*X qui seront ge're's par Le-Lisp ----------------------------------------------------------- */ inton () { if ( lldebug == 0 ) { if (realterminal != 0) signal(SIGINT, ll←break); /* interrupt */ signal(SIGILL, ll←merro); /* illegal instruction */ signal(SIGBUS, ll←merro); /* bus error */ signal(SIGSEGV, ll←merro); /* segmentation violation */ signal(SIGTRAP, ll←merro); /* trace trap */ signal(SIGFPE, ll←merro); /* floating point exception */ signal(SIGALRM, ll←clock); /* alarm clock */ #ifdef BSD42 signal(SIGTSTP, onstop42); signal(SIGCONT, oncont42); sigsetmask(0); #endif BSD42 #ifdef IBMRT signal(SIGDANGER, ll←merro); /* impending lack of page space */ #endif IBMRT } } /* intoff: de'sarme les signaux UN*X ge're's par Le-Lisp ----------------------------------------------------- */ /* ?!?!?! ou` est le code S5 ?!?!? */ intoff () { if ( lldebug == 0 ) { #ifdef BSD42 #define mask(s) (1 << ((s)-1)) return(sigblock (mask (SIGALRM) | mask(SIGINT))); #else BSD42 if (realterminal != 0) signal(SIGINT, SIG←IGN); #endif BSD42 } } /******************************************* INLELISP (pour ne pas dire MAIN !!) point d'entree de Le-Lisp *******************************************/ inlelisp(argc, argv, envp) int argc; char **argv, **envp; { int n, size; int verbose=0; #ifdef EXECORE int selfcore = 0; #endif EXECORE #ifdef EXECORE envpini = envp; /* sauvegarde de l'environnement Shell */ #endif EXECORE init←signal(); /* initialisation des signaux */ filin = FILEINI; /* initialisation des valeurs par defaut */ filit = FILIT; llban = LLBAN; nbsyst = NBSYST; #ifdef HP9300 lelisp←racine = LELISPDIR; #endif HP9300 /* De'cryptage des arguments Le premier argument est TOUJOURS le path absolu de lelispbin L'argument 0 est le path absolu du binaire */ strcpy(lelispbin, argv[0]); #define suitarg() ((++n >= argc) ? usage() : *(argv+n)) #define checkarg(s) (!strcmp(s,*(argv+n))) for(n = 1; n < argc; n++){ if((**(argv+n) >= '0') && (**(argv+n) <= '9')) { SCONS = atoi(*(argv+n)); continue; } if(**(argv+n) == '-'){ #ifdef EXECORE if(checkarg("-c")){ selfcore = 1; continue; } #endif EXECORE if(checkarg("-s")){ llban = 1; continue; } if(checkarg("-r")) { filit = 1; filin = suitarg(); continue; } if(checkarg("-debug")) { lldebug = 1; continue; } if(checkarg("-v")) { verbose = 1; continue; } if(checkarg("-stack")) { SSTACK = atoi(suitarg()); continue; } if(checkarg("-code")) { SCODE = atoi(suitarg()); continue; } if(checkarg("-heap")) { SHEAP = atoi(suitarg()); continue; } if(checkarg("-number")) { SNUMB = atoi(suitarg()); continue; } if(checkarg("-float")) { SFLOAT = atoi(suitarg()); continue; } if(checkarg("-vector")) { SVECT = atoi(suitarg()); continue; } if(checkarg("-string")) { SSTRG = atoi(suitarg()); continue; } if(checkarg("-symbol")) { SSYMB = atoi(suitarg()); continue; } if(checkarg("-cons")) { SCONS = atoi(suitarg()); continue; } if(checkarg("-ucons")) { UCONS = atoi(suitarg()); continue; } (void) usage(); } filit = 0; filin = *(argv+n); } filiz=strlen(filin); if( lldebug == 0 ) init←stty(); /* initialisation du terminal */ sstack = SSTACK * KPTR; scode = SCODE * 1024; sheap = SHEAP * 1024; snumb = SNUMB * KPTR; sfloat = SFLOAT * KPTR * 2; svect = SVECT * KPTR * 2; sstrg = SSTRG * KPTR * 2; ssymb = SSYMB * KPTR * 8; /* symbole = 8 pointeurs */ scons = SCONS * KPTR * 16; /* c'est en 8K CONS */ scons += UCONS * PTR * 64; /* c'est en paquet de 32 CONS*/ /* Verifications des arguments. Les zones FLOAT (flottants 31 bits) et NUMB (Toutes machines) peuvent e↑tre demande'es vides */ align(snumb); align(sfloat); align(scode); #define nozero(zone, nom) if(zone == 0) zonevide(nom) nozero(sstack,"stack"); align(sstack); nozero(sheap,"heap"); align(sheap); nozero(svect,"vector"); align(svect); nozero(sstrg,"string"); align(sstrg); nozero(ssymb,"symbol"); align(ssymb); nozero(scons,"cons"); align(scons); /* Calcul de la taille de la me'moire */ stbin = scons / 64; /* taille de la table des bits invisibles */ align(stbin); stbgc = (snumb+sfloat+svect+sstrg+ssymb+scons)/64; /* bits GC */ align(stbgc); /* en 2 coups a cause des limites de certains compilos C */ size = sstack+scode+sheap+svect; size = size+snumb+sfloat+sstrg+ssymb+scons+stbin+stbgc; if ( verbose ) {printf("FILIT %3d\r\n", filit); printf("FILIN %s\r\n", filin); printf("Tailles des zones me'moires (octets)\r\n"); printf("pile %8d\r\n", sstack); printf("code %8d\r\n", scode); printf("tas %8d\r\n", sheap); printf("nombres %8d\r\n", snumb); printf("flottants %8d\r\n", sfloat); printf("vecteurs %8d\r\n", svect); printf("strings %8d\r\n", sstrg); printf("symboles %8d\r\n", ssymb); printf("cons %8d\r\n", scons); printf("bits invisibles %8d\r\n", stbin); printf("bits de marquage %8d\r\n", stbgc); printf(" total %8d\r\n", size); } #ifdef EXECORE if(selfcore == 1){ corinit(); /* restauration turbo */ out(-1); /* au cas ou on rentrerait */ } #endif EXECORE if (filiz) { if (close(open(filin, 0)) != 0){ #ifdef FOREIGN fprintf(stderr, "Le-Lisp : cannot find file %s\r\n", filin); #else FOREIGN fprintf(stderr, "Le-Lisp : je ne trouve pas le fichier %s\r\n", filin); #endif FOREIGN out(-1); } #ifdef EXECORE if (filit == 1) { int dummy; int *pdummy; dummy = 1; pdummy = &dummy; prtmsgs = &pdummy; /* **prtmsgs existe */ corest(filin); out(-1); } #endif EXECORE } /* Allocation de la me'moire */ /* Pour pre'allouer ce qu'il faut pour un GETGLOBAL et e'viter que le MALLOC n'aille prendre de la place n'importe ou` */ #ifdef BSD4x (void) getgloba("start"); #endif BSD4x bmem = sbrk(0); bmem = (char *) (((long)bmem+PAGESIZE-1)&~(PAGESIZE-1)); (void) brk(bmem); bmem = sbrk(size); if(bmem == RATE){ #ifdef FOREIGN fprintf(stderr, "Le-Lisp : I can't get required memory space\r\n"); #else FOREIGN fprintf(stderr, "Le-Lisp : Impossible d'allouer tant de memoire\r\n"); #endif FOREIGN out(-1); } END = sbrk(0); /* pour voir si malloc prend de la place */ /* chargement des variables pre'de'finies */ estack = bmem + (4 * PTR); /* tole'rance minimale */ mstack2 = estack + (128 * PTR); /* Full Stack non re'cupe'rable */ mstack1 = estack + (1024 * PTR); /* Full Stack re'cupe'rable */ bstack = estack + sstack - PTR; bcode = bstack + PTR; ccode = bcode; ecode = bcode + scode; bheap = ecode; cheap = bheap; eheap = bheap + sheap; bnumb = eheap; cnumb = bnumb; bfloat = bnumb + snumb; cfloat = bfloat; bvect = bfloat + sfloat; cvect = bvect; bstrg = bvect + svect; cstrg = bstrg; bsymb = bstrg + sstrg; csymb = bsymb; bcons = bsymb + ssymb; econs = bcons + scons; ccons = bcons; btbin = econs; btbgc = btbin + stbin; emem = btbgc; /* et on y va !!! */ llstdio(); lisp←stty(); host←start(); /* au retour (si l'on rentre) on sort joliement */ out(0); } /********************************************************** L E S I M A G E S M E M O I R E S **********************************************************/ /* l'instruction LLM3 CORSAV doit positionner les 4 variables: bllm3, ellm3 limites de la zone impure LLM3 llucode fin de la zone code utilise'e lluheap fin de la zone heap utilise'e */ char *bllm3, *ellm3; /* Pour ne faire que des petites entrees/sorties (cf NFS ...) */ #ifndef WRITESIZE #define WRITESIZE 8192 #endif WRITESIZE WRITE(fd,where,length) int fd, length; char *where; { int cc, n; /* Si on veut une trace e'crite: */ /* printf("WRITE: %d %x %x \r\n", fd, where, length); */ n = length; while(n >= WRITESIZE) { if ((cc = write(fd, where, WRITESIZE)) < 0) return(cc); where += cc; n -= cc; } while(n > 0) { if ((cc = write(fd, where, n)) < 0) return(cc); where += cc; n -= cc; } return(length); } /************************************ Les images me'moires en mode EXECORE ************************************/ #ifdef EXECORE /* Point de lancement effectif */ extern llcorgo(); /* dans ../<system>/ll<system>.llm3 */ /* Variables positionnees au moment du save-core BSD4x */ int corscons; /* taille des CONS de l'image me'moire */ int corstbin; /* bits invisibles de l'image me'moire */ char *corbtbin; /*********** Le lancement direct (lelispbin -c) d'une image me'moire re'alise'e en mode EXECORE. ***********/ extern corinit(); corinit () { int diffcons; int diffmem; int i; if (scons > corscons) { if (sbrk(0) != END) #ifdef FOREIGN fprintf (stderr, "Le-Lisp : I can't allocate space without hole\r\n"); #else FOREIGN fprintf (stderr, "Le-Lisp : je ne peux pas allouer de la place sans trou\r\n"); #endif FOREIGN else { /* l'image memoire est plus petite que lelisp courant */ diffcons = (scons - corscons); /* bits invisibles */ diffmem = diffcons + (diffcons / 64); /* bits du GC */ diffmem += diffcons / 64; align(diffmem); if (sbrk(diffmem) == RATE) { #ifdef FOREIGN fprintf (stderr, "Le-Lisp : not enough ressources to allocate space\r\n"); #else FOREIGN fprintf (stderr, "Le-Lisp : Impossible de vous fournir tant de place\r\n"); #endif FOREIGN out(-1); } econs += diffcons; btbin = econs; for (i = corstbin; --i >= 0;) btbin[i] = corbtbin[i]; btbgc = btbin + stbin; END = sbrk(0); } } inton(); llcorgo(); } /********** Save-core en mode EXECORE ***********/ struct exec entete; char corbuf[1024]; extern int errno; int corsav (nom) char *nom; { int fd, fdbin; long symbols; long bout; int n, wr; llglobb("","",-1); /* pour tuer un sous-sh */ /* positionne les variables pour le restore-core */ corscons = scons; corbtbin = btbin; corstbin = stbin; if((fdbin = open(lelispbin, 0)) == -1) errreturn(lelispbin, 1); read(fdbin, &entete, sizeof (struct exec)); if((fd = creat(nom, 0777)) /* rwxrwxrwx | umask */ == -1){ if(errno != ETXTBSY) errreturn(nom, 1); if(unlink(nom) == -1) errreturn(nom, 1); if((fd = creat(nom, 0777)) /* rwxrwxrwx | umask */ == -1) errreturn(nom, 1); } bout = (long) sbrk(0); /* c'est la table des symboles de lelispbin qui nous interesse, Il faut la calculer avant de changer le champ entete.a←data */ symbols = N←SYMOFF(entete); entete.a←data = bout - N←DATADDR(entete); entete.a←bss = 0; entete.a←magic = ZMAGIC; /* le header */ write(fd, &entete, sizeof(struct exec)); #ifdef SEQUENT /* recopie du texte */ n = N←DATAOFF(entete) - sizeof(struct exec); while (n >= 1024) { read(fdbin, corbuf, 1024); WRITE(fd, corbuf, 1024); n -= 1024; } read(fdbin, corbuf, n); WRITE(fd, corbuf, n); WRITE(fd, entete.a←text, llucode - entete.a←text); /* le bas de lisp */ #else SEQUENT #ifdef VAXUNIX lseek(fd, N←TXTOFF(entete), 0); /* va au debut du texte */ write(fd, 0L, llucode); /* le bas de lisp */ #endif VAXUNIX #endif SEQUENT #ifdef VAXUNIX || SEQUENT lseek(fd, bheap-llucode, 1); /* le trou fin de code */ WRITE(fd, bheap, lluheap-bheap); /* le tas */ lseek(fd, bnumb-lluheap, 1); /* le trou fin de tas */ WRITE(fd, bnumb, econs-bnumb); /* le reste */ WRITE(fd, btbin, stbin); /* les bits invisibles */ lseek(fd, bout-(long)btbin-stbin, 1); #else VAXUNIX || SEQUENT /* recopie du texte */ n = entete.a←text - sizeof(struct exec); while (n >= 1024) { read(fdbin, corbuf, 1024); wr=write(fd, corbuf, 1024); if(wr != 1024) { perror ("save-core1"); exit(1); } n -= 1024; } read(fdbin, corbuf, n); wr=write(fd, corbuf, n); if(wr != n) { perror ("save-core1.1"); exit(1); } /* le data */ wr=write(fd, N←DATADDR(entete), bout - N←DATADDR(entete)); if(wr != (int)bout-N←DATADDR(entete)) { perror ("save-core2"); exit(1);} #endif VAXUNIX || SEQUENT /* le symbol */ /* on ajuste, normalement 0 sauf sur Sequent */ lseek(fdbin, symbols, 0); while ((n = read(fdbin, corbuf, 1024)) > 0) WRITE(fd, corbuf, n); close(fdbin); close(fd); /* chmod(nom, 493); -rwxr-xr-x Pour garder le umask du user (creat).*/ return(0); } /********** Restore-core en mode EXECORE ***********/ char *corargv[5] = { "lelispbin", "003", "003", "-c", 0}; int corest (nom) char *nom; { int fd, i; corargv[0] = nom; /* convention Unix */ if ((fd = open(nom, 0)) == -1) errreturn(nom, 1); close(fd); sprintf(corargv[2], "%d", scons/(8*8*1024)); execve(nom, corargv, envpini); errreturn (nom, 1); } #else EXECORE /************************************* Les images me'moires en mode standard ************************************* L'ente↑te des fichiers image-me'moire contient : - 3 mots d'identification (12 caracte`res) - les tailles des zones de l'image me'moire corsstack corscode corsheap corsnumb corsfloat corsvect corsstrg corssymb corscons corstbin - les tailles des bouts me'moires sauve's sllm3 ucode uheap urest */ #define ID "lelisp core " struct ENTETE { char idlelisp[12]; int corsstack; int corscode; int corsheap; int corsnumb; int corsfloat; int corsvect; int corsstrg; int corssymb; int corscons; int corstbin; int sllm3; int ucode; int uheap; int urest; } entete; /********** Save-core en mode standard ***********/ int corsav (nom) char *nom; { int fd; if((fd = creat(nom, 511)) == -1) errreturn(nom, 1); strncpy(entete.idlelisp, ID, 12); entete.corsstack = sstack; entete.corscode = scode; entete.corsheap = sheap; entete.corsnumb = snumb; entete.corsfloat = sfloat; entete.corsvect = svect; entete.corsstrg = sstrg; entete.corssymb = ssymb; entete.corscons = scons; entete.corstbin = stbin; entete.sllm3 = ellm3 - bllm3; entete.ucode = llucode - bmem; entete.uheap = lluheap - bheap; entete.urest = econs - bnumb; if(WRITE(fd, &entete, sizeof(struct ENTETE)) != sizeof(struct ENTETE)){ /* entete */ close(fd); errreturn(nom, 1); } if((WRITE(fd, bllm3, entete.sllm3)) != entete.sllm3){ /* variables LLM3 */ close(fd); errreturn(nom, 1); } if((WRITE(fd, bmem, entete.ucode)) != entete.ucode){ /* code utilise' */ close(fd); errreturn(nom, 1); } if((WRITE(fd, bheap, entete.uheap)) != entete.uheap){ /* heap utilise' */ close(fd); errreturn(nom, 1); } if((WRITE(fd, bnumb, entete.urest)) != entete.urest){ /* zones lisp */ close(fd); errreturn(nom, 1); } if((WRITE(fd, btbin, entete.corstbin)) != entete.corstbin){ /* bits invisibles */ close(fd); errreturn(nom, 1); } if (close(fd) < 0) errreturn("Le-Lisp",1); return(0); } /********** Restore-core en mode standard ***********/ int READ(fd,where,length) int fd, length; char *where; { int cc, n; /* Si on veut une trace e'crite: */ /* printf("READ: %d %x %x \r\n", fd, where, length); */ return(read(fd, where, length)); } int corest (nom) char *nom; { int fd; if((fd = open(nom, 0)) == -1) errreturn(nom, 1); if(READ(fd, &entete, sizeof(struct ENTETE)) != sizeof(struct ENTETE)){ /* lit l'entete */ close(fd); errreturn(nom, 1); } if(strncmp(entete.idlelisp, ID, 12)){ /* chai↑ne d'identification */ #ifdef FOREIGN fprintf(stderr, "Le-Lisp : %s is not a core image\r\n", nom); #else FOREIGN fprintf(stderr, "Le-Lisp : %s n'est pas une image memoire\r\n", nom); #endif FOREIGN close(fd); if ((prtmsgs == 0) || (*prtmsgs == 0)) out (-1); errreturn(nom, 1); } if((entete.corsstack != sstack) || (entete.corscode != scode) || (entete.corsheap != sheap) || (entete.corsnumb != snumb) || (entete.corsfloat != sfloat) || (entete.corsvect != svect) || (entete.corsstrg != sstrg) || (entete.corssymb != ssymb)){ /* les tailles fixes */ #ifdef FOREIGN fprintf(stderr, "Le-Lisp : non compatible core image : %s\r\n", nom); #else FOREIGN fprintf(stderr, "Le-Lisp : image memoire non compatible : %s\r\n", nom); #endif FOREIGN close(fd); if ((prtmsgs == 0) || (*prtmsgs == 0)) out (-1); errreturn(nom, 1);} if(entete.corscons > scons){ /* trop gros ? */ #ifdef FOREIGN fprintf(stderr, "Le-Lisp : core image too large : %s\r\n", nom); #else FOREIGN fprintf(stderr, "Le-Lisp : image memoire trop grosse : %s\r\n", nom); #endif FOREIGN close(fd); errreturn(nom, 1); } if((READ(fd, bllm3, entete.sllm3)) != entete.sllm3){ /* variables LLM3 */ close(fd); errreturn(nom, 1); } if((READ(fd, bmem, entete.ucode)) != entete.ucode){ /* code utilise' */ close(fd); errreturn(nom, 1); } if((READ(fd, bheap, entete.uheap)) != entete.uheap){ /* heap utilise' */ close(fd); errreturn(nom, 1); } if((READ(fd, bnumb, entete.urest)) != entete.urest){ /* zones lisp */ close(fd); errreturn(nom, 1); } if((READ(fd, btbin, entete.corstbin)) != entete.corstbin){ /* bits invisibles */ close(fd); errreturn(nom, 1); } close(fd); return(0); } #endif EXECORE /********************************************************** cline: Envoi d'une commande au SHELL **********************************************************/ cline (buff) char *buff; { char *dir; if (!strncmp(buff, "cd", 2)) { /* c'est peut-etre un cd */ dir = buff + 1; while (*++dir == ' ') /* void */ ; if (*dir=='\0') cchdir(getenv("HOME")); /* cd tout court */ else if (dir != buff+2) if (!cchdir(dir)) /* cd PATH */ return (0); } unix←stty(); system(buff); lisp←stty(); inton(); } system(s) char *s; { int status, pid, w; #ifdef BSD4x pid=vfork(); /* on forke astucieusement */ #endif #ifdef S5 pid =fork(); /* on ne vforke pas en systeme 5 */ #endif if (pid == 0) { {int f; for(f = 3;f < 10; f++) (void) close(f); /* parano ! */ } int←std(); execl("/bin/sh", "sh", "-c", s, 0); ←exit(127); } int←ign(); while ((w = wait(&status)) != pid && w != -1) ; if (w == -1) status = -1; return(status); } /* runtime ======= Retourne le temps depuis le debut du job. Ce temps est en secondes (flottant). L'unite' de temps de'pend du syste`me */ #ifndef TIMEUNIT #ifdef BSD4x #define TIMEUNIT 60. #endif BSD4x #ifdef S5 #define TIMEUNIT 1000. #endif S5 #endif TIMEUNIT #ifdef BSD42 double runtime() { struct rusage urusage; struct timeval utimeval; getrusage(0, &urusage); utimeval = urusage.ru←utime; return(utimeval.tv←sec+(utimeval.tv←usec/1000000.)); } #else BSD42 double runtime() { struct tms timebuffer; times(&timebuffer); return (timebuffer.tms←utime / TIMEUNIT); } #endif BSD42 /* sleep ======= Dort n secondes. Ce temps est en secondes (flottant). Helas UN*X ne peut dormir qu'un nb de sec fixes */ /* En 31bitfloats: l'argument est dans accusingle1 */ csleep() { unsigned seconds; seconds = accusingle1; sleep(seconds); } /* En 64bitfloats: l'argument est en argument(dans la pile) */ cdleep(f) double f; { unsigned seconds; seconds = f; sleep(seconds); } /* cdate ===== Donne la date courante */ extern struct tm *localtime(); cdate (date←lisp) int *date←lisp; { struct tm decoded; long clock; clock = time(0); decoded = *localtime(&clock); date←lisp[0] = decoded.tm←year + 1900; date←lisp[1] = decoded.tm←mon + 1; date←lisp[2] = decoded.tm←mday; date←lisp[3] = decoded.tm←hour; date←lisp[4] = decoded.tm←min; date←lisp[5] = decoded.tm←sec; date←lisp[7] = decoded.tm←wday == 0 ? 7 : decoded.tm←wday; } /* setalarm ======== De'clenche une alarme apre`s n secondes (flottant). */ double setalarm(f) double f; { #ifdef BSD42 struct itimerval nit,oit; register int secs; secs = (long) (f * 1e+6); /* marche si f < 1000000 s ! */ timerclear(&nit.it←interval); nit.it←value.tv←sec = secs / 1000000; nit.it←value.tv←usec = secs % 1000000; if (setitimer(ITIMER←REAL, &nit, &oit) < 0) return(0); return(oit.it←value.tv←sec + oit.it←value.tv←usec * 1e-6); #else BSD42 #ifdef SPS7 /* sur SMX 5.1 il y a un hack pour avoir une horloge au 1/1000ieme */ register int secs; extern int alarm←on; secs = (long) (f * -1000.); if ((secs == 0) && (f != 0.)) secs = -1; /* pour l'arrondi */ return((double) alarm(secs)); #else SPS7 register int secs; extern int alarm←on; secs = (long) f; alarm←on = f == 0. ? 0 : 1; if ((secs == 0) && (f != 0.)) secs = 1; /* pour l'arrondi */ return((double) alarm(secs)); #endif SPS7 #endif BSD42 } /* getenvrn ======== Recherche d'une variable de l'environnement. Rempli le buffer donne argument avec la chaine resultat. Retourne la taille de la chaine. */ extern char *getenv(); int getenvrn (nom, buff) char *nom, *buff;{ char *u; if(nom = (u = getenv(nom))){ while(*buff++ = *u++); return (u-nom-1); } return (0); } /* getgloba ========= retourne la valeur associee a un symbole dans la table des symboles de l'image Le-Lisp. */ /* la macro NLISTNAME permet de positionner le champ n←name d'un e'le'ment de table des symboles. Ca depend beaucoup des systemes... */ #ifdef BSD4x #define NLISTNAME(e,i,s) e[i].n←un.n←name = s #endif BSD4x #ifdef Perkin #define NLISTNAME(e,i,s) strncpy(e[i].n←name,s,8) #endif Perkin #ifdef CADMUS #define NLISTNAME(e,i,s) strcpy(e[i].n←name, s) #endif CADMUS #ifdef HP9300 #define NLISTNAME(e,i,s) e[i].n←name = (*s == 0) ? NULL : s #endif HP9300 #ifdef UNIGRAPH | LEWS #define NLISTNAME(e,i,s) e[i].n←name = (*s == 0) ? s : s+1 #endif UNIGRAPH /* le defaut */ #ifndef NLISTNAME #define NLISTNAME(e,i,s) e[i].n←name = s #endif NLISTNAME struct nlist elem[2]; int getgloba (strg) char *strg; { NLISTNAME(elem, 0, strg); NLISTNAME(elem, 1, ""); nlist(lelispbin, elem); return(elem[0].n←value); } /* le getglobal multiple */ struct lisp←string { char *pad1; char *pad2; char chars; }; struct lisp←cons { struct lisp←string **car; struct lisp←cons *cdr; }; void mgetglo (list, nil) struct lisp←cons *list, *nil; { int length, i; struct lisp←cons *courant; struct nlist *elems; char *name; length = 0; for (courant = list; courant != nil; courant = (struct lisp←cons *)courant->cdr) length++; elems = (struct nlist *) malloc ((length+1) * sizeof(struct nlist)); i = 0; for (courant = list; courant != nil; courant = (struct lisp←cons *) courant->cdr) { name = &((*(courant->car))->chars); NLISTNAME(elems, i, name); i++; } NLISTNAME(elems, i, ""); nlist (lelispbin, elems); i = 0; for (courant = list; courant != nil; courant = (struct lisp←cons *) courant->cdr) { courant->car = (struct lisp←string **) elems[i].n←value; i++; } free(elems); } /* la routine de sortie */ out(code) int code; { if(!strncmp(lelispbin, template, 12)) unlink(lelispbin); unix←stty(); exit(code); /* puis sort avec code de retour */ } outner () { /* sortie normale depuis lisp */ out(0); } outwer () { /* sortie anormale depuis lisp */ out(-1); /* suivant la convention UNIX */ } outcore() { perror("Le-Lisp : restore-core : "); out(-1); } /* la syntaxe d'appel de Le-Lisp sous UN*X */ char *usage() { fprintf(stderr, "Usage : lelisp [-s] [file] [-r file] [number] \ [-stack number] [-code number] [-heap number] [-float number] \ [-vector number] [-string number] [-symbol number] [-cons number]\r\n"); out(-1); return((char *)-1); } zonevide(s){ #ifdef FOREIGN fprintf(stderr, "Empty %s zone\r\n", s); #else FOREIGN fprintf(stderr, "Zone %s vide\r\n", s); #endif FOREIGN out(-1); } /* Le chargement dynamique de modules C Courtesy of L. Fallot Revu par M. Devin */ #define wwe(s) write(2,s,strlen(s)) #define round(x,s) ((((x)-1) & ~((s)-1)) +(s)) #ifndef S5 char * cload(file, ccode, ecode) char *file, *ccode, *ecode;{ char *ccoderound; int taille; int totale; char cbuf[512]; int fd; struct exec header; int i; /* remettre 6 X au bout du template et ge'ne'rer un nom unique */ for(i = strlen(template)-6; i < strlen(template); i++) template[i] = 'X'; mktemp(template); /* arrondir ccode a` la taille de la page */ #ifdef SPS9 ccoderound = (char *)round((int)ccode, 4096); #else SPS9 #ifdef SEQUENT ccoderound = (char *)round((int)ccode, 2048); #else SEQUENT ccoderound = (char *)round((int)ccode, 512); #endif SEQUENT #endif SPS9 /* appeler le linker */ sprintf(cbuf, #ifdef SPS9 "/bin/ld -C -A %s -N -x -T %x -o %s %s -lc", #else SPS9 #ifdef SUNOS40 "/bin/ld -A %s -Bstatic -N -x -T %x -o %s %s -lc", #else SUNOS40 "/bin/ld -A %s -N -x -T %x -o %s %s -lc", #endif SUNOS40 #endif SPS9 lelispbin, ccoderound, template, file); cline(cbuf); /* Le link est-il bien fini ? */ fd = open(template, 0); if (fd < 0) { perror(template); unlink(template); return(ccode); } if(read(fd,&header,sizeof(header)) != sizeof(header)) { perror(template); close(fd); unlink(template); return(ccode); } /* le programme ge'ne're' tient-il dans la zone code ? */ taille = round(header.a←text, 4) + round(header.a←data, 4); totale = taille + header.a←bss; #ifdef SPS9 totale = round(totale, 4096); #else SPS9 #ifdef SEQUENT totale = round(totale, 2048); #else SEQUENT totale = round(totale, 512); #endif SEQUENT #endif SPS9 if((ccoderound+totale) >= ecode){ fprintf(stderr, #ifdef FOREIGN "cload: fatal error full code zone: missing %d Kbytes\r\n", #else FOREIGN "cload: erreur fatale zone code pleine: il manque %d Koctets\r\n", #endif FOREIGN ((ccoderound+totale-ecode))/1024+1); return(ccode); } if (taille != read(fd,ccoderound,taille)) { perror(template); close(fd); unlink(template); return(ccode); } close(fd); if(!strncmp(lelispbin, template, 12)) unlink(lelispbin); strcpy(lelispbin, template); return(ccoderound+totale); } #endif S5 /* le repertoire courant */ int llgetwd (s, l) char *s; int l; { int code; #ifdef VAXUNIX code = getwd(s); /* maxpathlen is the max */ #else VAXUNIX code = getcwd(s, l); #endif VAXUNIX return(code ? strlen(s) : 0); } /* Les tests pour callextern */ int cchdir (strg) char *strg; { return(llglobb(strg,"",0)); } char *chome () { return(getenv("HOME")); } #ifdef BSD42 char *date () { char *s; long temps; temps = time(0); s = ctime(&temps); *(s+24) = '\0'; return(s); } #endif BSD42 #ifdef SPS9 #include "lelisp.h" struct LL←SYMBOL *ll←concat; struct LL←SYMBOL * getsym (s) char *s; { pusharg(LLT←STRING, s); return (struct LL←SYMBOL *) lispcall (LLT←T, 1, ll←concat); } #endif SPS9 int cmoinsun () { return(-1); } double ctest (strg,nf,ni,vect) char *strg; double nf; int ni; int *vect;{ int i; printf("la chaine est %s\r\n", strg); printf("le flottant est %e\r\n", nf); printf("l'entier est %d\r\n", ni); printf("le vecteur contient vect[0]=%8x,vect[1]=%8x\r\n", vect[0], vect[1]); i = vect[0]; vect[0] = vect[1]; vect[1] = i; return(nf*ni); } cboucle () { while (1) sin(3.14); } /* * newer * ===== * Lists both of its arguments newer first. * For CAML module system. */ static time←t fdate(name) char *name; { struct stat stbuf; if (stat(name, &stbuf) == -1) { return(-1); } return(stbuf.st←mtime); } newer(name1,name2) char *name1; char *name2; { time←t date1; time←t date2; date1 = fdate (name1); date2 = fdate (name2); if (date1 == -1) if (date2 == -1) return(-3); else return(-1); if (date2 == -1) return(-2); return(date1 > date2); } /* Ce paragraphe contient le mecanisme de wildcarding implemente sur BSD4.2 (SUN) . Il essaie d'etre relativement efficace. la premiere invocation cree un sous process cshell par vfork les fois suivantes , on se contente de piper les noms a expanser et a recuperer les chaines expansees, apres quoi, lisp en fait ce qu'il veut.... Auteur : Michel DANA Date : 26 Aout 1988 Modif : 31 Aout 1988 pour adaptation SYSTEM 5 */ #define MAXLINE 1024 int llglobb (ll←in←string,ll←out←string,maxline) char *ll←in←string, *ll←out←string ; { static int pipe←in[2],pipe←out[2],first←time=0,pid=0; static int incopy, outcopy; static char *s; static FILE *stream←in, *stream←out; static char buff[MAXLINE]; int i; /* EN */ if (maxline==0) /* chdir */ {if (chdir(ll←in←string)) return(-1); /* chdir pour le process-meme */ if (first←time==0) return(0); /* pas de sous-shell */ }; /* on en reste la */ if (maxline==-1) /* destruction du sous-shell */ {if (first←time==0) /* meme pas cree encore */ return(0); /* on en reste la */ fclose(stream←out); /* on ferme fd vers le sh */ i=wait(0); /* le sous-sh est mort */ fclose(stream←in); /* on ferme le fd venant du sh */ first←time=0; /* on revient a l'etat */ return(i);}; /* on en reste la */ if (first←time==0){ /* c'est la premiere fois, il y a des choses a initialiser */ if (maxline==0) /* chdir? */ return(chdir(ll←in←string)); /* nouvelle directory */ if (pipe(pipe←in) || pipe(pipe←out)) /* erreur? */ return(-7); /* retour lelisp */ incopy=dup(0); /* copie pour cline .... */ outcopy=dup(1); /* ... redirige par <> dans sh */ first←time=1; #ifdef BSD4x pid=vfork(); /* on forke astucieusement */ #endif #ifdef S5 pid =fork(); /* on ne vforke pas en systeme 5 */ #endif if (pid<0) return(-8); /* erreur? retour lelisp */ if (pid==0) { /* je suis le fils */ close(pipe←in[1]); /* faut pas oublier */ close(pipe←out[0]); /* ces deux inutiles-la */ #ifdef BSD4x dup2(pipe←in[0],0); /* je reassigne stdin */ dup2(pipe←out[1],1); /* la meme chose sur stdout */ #endif #ifdef S5 fclose(stdin); fclose(stdout); dup(pipe←in[0]); dup(pipe←out[1]); #endif /* freopen("/dev/null","w",stderr); pour ne pas avoir de messages */ /* bizarres en cas d'echec */ execl ("/bin/sh","sh",0); /* sh existe partout */ } /* le pere maintenant */ close(pipe←in[0]); close(pipe←out[1]); /* inutile de conserver des descripteurs */ /* inutiles */ stream←in=fdopen(pipe←out[0],"r"); stream←out=fdopen(pipe←in[1],"w"); #ifdef BSD4x setlinebuf(stream←out); /* fin des initialisations */ #endif #ifdef S5 setbuf(stream←out,NULL); /*pas de bufferisation....*/ #endif fputs("trap '' 2\n", stream←out); /* contre les ↑C de Lelisp */ close(incopy); /* seul utilise par le fils */ close(outcopy); } if (kill(pid,0)<0) /* le pid, est-il la? */ {fclose(stream←out); /* non, on ferme */ fclose(stream←in); /* les filedesc */ first←time=0; /* pret a recommencer */ if (maxline == 0) return(0); /* chdir?, pas d'erreur */ return(-9);}; /* retour Lelisp */ if (maxline == 0) /* chdir, suite */ {fprintf( /* on compose une commande cd */ stream←out, /* vers le sous-sh */ "cd %s\n", /* le template */ ll←in←string); /* la directory */ return(0);}; /* on en reste la */ if (maxline==-2) /* on simule cline */ {int←ign(); /* prolog de ... */ unix←stty(); /* .. cline */ fprintf /* on construit la commande */ (stream←out, /* vers le sous-sh */ "sh -c 'exec <&%d >&%d; %s'\n", /* recuperation de ... */ incopy, /* ... stdin ...*/ outcopy, /* ... stdout */ ll←in←string); /* la commande-cline */ fprintf(stream←out,"echo $?\n"); /* imprime exit-status */ fscanf(stream←in,"%d",&i); /* recupere exit-status */ lisp←stty(); /* epilog de ... */ inton(); /* ... cline */ return(i);}; /* synchronise' */ s= & buff[0]; buff[0]='\0'; strcat(&buff[0],"echo ll: "); strcat(&buff[0],ll←in←string); strcat(&buff[0],"\n"); /* printf("on passe %s \n",&buff[0]); */ fputs(s ,stream←out); while (strncmp(s=fgets(buff,maxline,stream←in),"ll: ",4)); /* on */ /* tout */ /* garbage */ s=s+4; strcpy(ll←out←string,s); return(strlen(ll←out←string)); }