/***************************************************************************** Gestionnaire de terminal Unix: gets.c (c) Pierre ADRIAANS 1994 *****************************************************************************/ #include "gets.h" /* Macro de sauvegarde/restauration d'une eventuelle interruption systeme sur l'horloge. Elles ont pour but d'empecher les affichages de cette interruption (typiquement un affichage de l'heure toutes les secondes) d'interferer avec un rafraichissement d'ecran */ unsigned int GetsRemains; #ifdef SIGACT struct sigaction GetsOldAlrm,GetsNewAlrm; #define SaveAlrm() \ { GetsNewAlrm.sa_handler = SIG_IGN; \ sigemptyset(&GetsNewAlrm.sa_mask); \ GetsNewAlrm.sa_flags = 0; \ sigaction(SIGALRM,&GetsNewAlrm,&GetsOldAlrm); \ if(GetsOldAlrm.sa_handler != SIG_IGN) GetsRemains = alarm(0); \ else GetsRemains = 0; } #define RestoreAlrm() \ { sigaction(SIGALRM,&GetsOldAlrm,&GetsNewAlrm); \ if(GetsOldAlrm.sa_handler != SIG_IGN) alarm(GetsRemains); } #else void (*GetsAlrmFct)(int); #define SaveAlrm() \ { GetsAlrmFct = signal(SIGALRM,SIG_IGN); \ if(GetsAlrmFct != SIG_IGN) GetsRemains = alarm(0); \ else GetsRemains = 0; } #define RestoreAlrm() \ { signal(SIGALRM,GetsAlrmFct); \ if(GetsAlrmFct != SIG_IGN) alarm(GetsRemains); } #endif int Gets(char *Str) { VideoEle_t *VM; /* La memoire video */ char *Buffer = (char *)NULL, /* Buffer de saisie */ *Buffer2 = (char *)NULL, /* Buffers pour les decalages a l'ecran lors */ *ShiftBuf, /* des delete et des backspace */ Color, /* Attribut d'affichage actif */ Insertion = 1; /* Temoin de mode de saisie: insertion ou overstrike */ int i, /* Offset d'insertion courante dans le Buffer de saisie */ LastCBuf, /* Offset du dernier caractere dans le Buffer */ TempBuf, /* Pointeur auxiliaire dans le Buffer */ LastAffX, /* Position a l'ecran du dernier caractere du Buffer */ Length, /* Longueur de l'eventuelle string contenue dans le buffer a l'entree dans la fonction */ Fini, /* Temoin de fin de saisie */ ReturnValue, /* Valeur de retour */ AfficheX,AfficheY, /* Position actuelle du curseur */ ViewX1,ViewY1, /* Fenetre active lors de la saisie */ ViewX2,ViewY2, OutCol, /* Colonne ou placer le curseur en fin de saisie: colonne de gauche de la fenetre active courante */ ActH,ActL, /* Hauteur et longueur de la fenetre active */ Offset, /* Calculs d'offset dans la memoire video */ KbKey, /* Touche lue au clavier */ NbreLig,NbreCol; /* Resolution de l'ecran */ /* Initialiser tout le monde */ GetScreenRes(&NbreLig,&NbreCol); Buffer = (char *)malloc(NbreCol+1); if(Buffer == (char *)NULL) raise(SIGME); Buffer2 = (char *)malloc(NbreCol+1); if(Buffer2 == (char *)NULL) raise(SIGME); ShiftBuf = Buffer2; GetActiveWindow(&ViewY1,&ViewX1,&ActH,&ActL); OutCol = ViewX1; ViewY2 = ViewY1 + ActH - 1; ViewX2 = ViewX1 + ActL - 1; GetXY(&AfficheY,&AfficheX); Color = GetCurrentAtt(); VM = GetVideoMemoryAdress(); Fini=0; Length=strlen(Str); strcpy(Buffer,Str); AfficheX=ViewX1+Length; /* Placer le curseur a la fin de la string */ LastAffX=AfficheX; i=Length; LastCBuf=Length; if(Length!=0) WriteString(Buffer,Color,AfficheY,ViewX1); GotoXY(AfficheY,AfficheX); /* Premiere entree: traitement particulier */ fflush(stdout); KbKey = ReadKbd(); LockKbd(); switch(KbKey) /* Sortir immediatement ? */ { case CR: Fini = 1; ReturnValue = 0; GotoXY(AfficheY+1,OutCol); break; case CTRL_C: case ESC: Fini = 1; ReturnValue = -1; break; default: ; } if(!Fini) /* Ce n'etais ni , ni */ { if(isdisplay(KbKey) || KbKey == DELETE || KbKey == K_REMOVE ) /* Reset buffer ? */ { AfficheX = ViewX1; LastAffX = AfficheX; ClrZone(AfficheY,AfficheX,1,ViewX2 - AfficheX,Color); i = 0; LastCBuf = 0; GotoXY(AfficheY,AfficheX); } else ; do /* Traitement de la premiere touche puis des suivantes */ { if( isdisplay(KbKey) && ((LastAffX <= ViewX2 && Insertion) || (AfficheX <= ViewX2 && !Insertion)) ) /* Traduction: Afficher si (c'est affichable) ET ((Si insertion, la fenetre n'est pas remplie) OU (Si ecrasement, la position d'ecriture courante n'est pas hors de la fenetre)) */ { if(Insertion) if(i != LastCBuf) /* Si Insertion et curseur au milieu: decalage a droite de la fin */ { TempBuf = LastCBuf; /* Transfert dans ShiftBuf de la string a partir de la position d'insertion courante jusqu'a la fin */ ShiftBuf = Buffer2; strncpy(ShiftBuf,Buffer+i,LastCBuf-i); ShiftBuf[LastCBuf-i] = 0; /* shift a droite dans le buffer de saisie */ for(;TempBuf>i;TempBuf--) Buffer[TempBuf] = Buffer[TempBuf-1]; /* Actualisation de l'affichage: impression de ShiftBuf une position plus a droite */ SaveAlrm(); GotoXY(AfficheY,AfficheX + 1); for(Offset = VidMemOffset(AfficheY,AfficheX + 1); *ShiftBuf; ShiftBuf++,Offset++) { VM[Offset].Code = *ShiftBuf; VM[Offset].Attr = Color; PutToScr(*ShiftBuf); } /* Replacer le curseur a son origine */ GotoXY(AfficheY,AfficheX); RestoreAlrm(); } else; else; /* Insertion du caractere dans le buffer de saisie */ Buffer[i] = (char)KbKey; i++; /* Affichage du caractere a l'ecran */ PutToScr((char)KbKey); Offset = VidMemOffset(AfficheY,AfficheX); VM[Offset].Code = (char)KbKey; VM[Offset].Attr = Color; if(Insertion || AfficheX == LastAffX) { LastCBuf++; /* Un caractere de plus: si insertion, tjs ++, */ LastAffX++; /* sinon, seulement si on est a la fin de la ligne */ } else; /* Le curseur a bouge */ AfficheX++; SetXY(AfficheY,AfficheX); } else /* Touche de controle */ { switch(KbKey) { case CTRL_I: case K_INS: Insertion = (char)(!Insertion); /* Changer de mode */ break; case BACKSP: /* Backspace */ if(AfficheX > ViewX1) { if(iViewX1) { AfficheX--; i--; } break; case K_RIGHT: if(i