/***************************************************************************** Application ASH: process.c (c) Pierre Adriaans 1994 ------------------------------------------------------------------------------ Fonction de gestion des processus *****************************************************************************/ #include "ash.h" /* Variables utilisees par Process() pour decripter le format d'affichage de la commande ps selectionnee */ extern char *ProgName, /* Nom du programme courant */ TermID[10], /* Terminal ou il tourne */ Pid[15]; /* pid */ /* Commande a accrocher a ps dans la recherche des processus */ extern char PS_Cmd[80]; /* Colonnes de chaque element */ extern int PidCol,TermIDCol,NameCol; /* Temoin d'utilisation du /proc */ extern int ProcSystemOn; /* SS-rep du /proc */ extern char ProcSystem[255]; extern AnswerBoxItem_t *InfoMsg; /* Liste des signaux */ extern ListBoxItem_t *Signals; /* String de manipulation */ extern char DummyStr[DUMMYSTR_SIZE]; /* Pout le split des lignes de sorties */ extern char *Args[NB_ARGS + 1]; /* LLB de stockage des lignes analysees et decortiquees */ struct ProcRec_s { char *Name, *Pid, *Term, Str[50]; struct ProcRec_s *Suivant; struct ProcRec_s *Prec; }; static struct ProcRec_s *ProcRec,*ProcCour,*ProcPrec, *ProcTemp,*ProcEnd,*ProcCurrent; static int ProcNbreEntries; /* Nombre de process */ #define NB_PROC_ARGS 200 /***************************************************************************** SearchForProcessWith_proc() ------------------------------------------------------------------------------ Gestion des processus: fonction de recherche utilisant /proc *****************************************************************************/ int SearchForProcessWith_proc() { static char stat_str[4096]; static char *ttgrp = " StuvPQRWpqrs"; static char *ttsub = "0123456789abcdef"; DIR *pDir = (DIR *)NULL; struct dirent *d = (struct dirent *)NULL; FILE *hf; int pid,fd,NbRead,i,tty; char *Args[NB_PROC_ARGS]; struct stat s; uid_t uid; char tty_str[10],pid_str[25],name_str[255]; struct passwd *pw; OpenWin(11,24,3,32,DoingNorm,SINGLE_FRAMED,SHADED); Printf(" Searching %s...",ProcSystem); fflush(stdout); uid = getuid(); pw = getpwnam("root"); for(i=0;id_ino != 0) { if(strcmp(d->d_name,".") == 0 || strcmp(d->d_name,"..") == 0) continue; strcpy(DummyStr,ProcSystem); strcat(DummyStr,"/"); strcat(DummyStr,d->d_name); stat(DummyStr,&s); if(uid != pw->pw_uid) if(s.st_uid != uid) continue; pid = atoi(d->d_name); if(pid < 1) continue; /* Pid */ strcpy(pid_str,d->d_name); /* Name */ strcpy(DummyStr,ProcSystem); strcat(DummyStr,"/"); strcat(DummyStr,d->d_name); strcat(DummyStr,"/"); strcat(DummyStr,"cmdline"); name_str[0] = 0; hf = fopen(DummyStr,"r"); if(hf != (FILE *)NULL) { fgets(name_str,79,hf); fclose(hf); } /* TTY */ strcpy(DummyStr,ProcSystem); strcat(DummyStr,"/"); strcat(DummyStr,d->d_name); strcat(DummyStr,"/"); strcat(DummyStr,"stat"); fd = open(DummyStr,O_RDONLY,0); if(fd != -1) { NbRead = read(fd,stat_str,4095); stat_str[NbRead] = 0; for(i = 0;i < NbRead;i++) if(stat_str[i] == 0) stat_str[i] = ' '; close(fd); } else continue; ConvertArgs(stat_str,Args,NB_ARGS); if(name_str[0] == 0) strcpy(name_str,Args[1]); tty = atoi(Args[6]); if(tty == -1) strcpy(tty_str," ? "); else if(tty == 0) strcpy(tty_str,"con"); else if(tty < 64) sprintf(tty_str,"v%02d",tty); else if(tty < 128) sprintf(tty_str,"s%02d",(tty - 64)); else { tty_str[0] = 'p'; tty_str[1] = ttgrp[(tty >> 4) & 017]; tty_str[2] = ttsub[tty & 017]; tty_str[3] = 0; } for(i=0;Args[i] != (char *)NULL && i < NB_ARGS;i++) { free(Args[i]); Args[i] = (char *)NULL; } ProcNbreEntries++; ProcTemp = (struct ProcRec_s *)malloc(sizeof(struct ProcRec_s)); if(ProcTemp == (struct ProcRec_s *)NULL) raise(SIGME); ProcTemp->Name = (char *)malloc(strlen(name_str) + 1); if(ProcTemp->Name == (char *)NULL) raise(SIGME); ProcTemp->Term = (char *)malloc(strlen(tty_str) + 1); if(ProcTemp->Term == (char *)NULL) raise(SIGME); ProcTemp->Pid = (char *)malloc(strlen(pid_str) + 1); if(ProcTemp->Pid == (char *)NULL) raise(SIGME); strcpy(ProcTemp->Name,name_str); strcpy(ProcTemp->Term,tty_str); strcpy(ProcTemp->Pid,pid_str); ProcTemp->Prec = (struct ProcRec_s *)NULL; if(strlen(ProcTemp->Name) < 28) strcpy(ProcTemp->Str,ProcTemp->Name); else { strcpy(ProcTemp->Str,"/..."); strcat(ProcTemp->Str,ProcTemp->Name + (strlen(ProcTemp->Name) - 23)); } for(i=strlen(ProcTemp->Str);i<33;i++) strcat(ProcTemp->Str," "); strcat(ProcTemp->Str,ProcTemp->Pid); for(i=strlen(ProcTemp->Str);i<45;i++) strcat(ProcTemp->Str," "); strcat(ProcTemp->Str,ProcTemp->Term); if(ProcRec == (struct ProcRec_s *)NULL) { ProcRec = ProcTemp; ProcRec->Suivant = (struct ProcRec_s *)NULL; } else { ProcTemp->Suivant = ProcRec; ProcRec->Prec = ProcTemp; ProcRec = ProcTemp; } } } CloseWin(); closedir(pDir); return(0); } /***************************************************************************** SearchForProcessWith_ps() ------------------------------------------------------------------------------ Gestion des processus: fonction de recherche utilisant le ps 1. Recuperation dans une LLU de strings des sorties ecran d'execution d'un ps execute par un processus fils. Le fils execute dans un pipe, le pere lit dans le pipe. 2. Analyse de ces sorties ecran pour determiner la colonne contenant le nom du programme, son pid et le numero du terminal. 3. Initialisation d'une LLB de structures avec chaque process repertorie *****************************************************************************/ int SearchForProcessWith_ps() { /* LLU de recuperation des sorties ecran du ps */ struct StrRec_s { char *Str; struct StrRec_s *Suivant; }; struct StrRec_s *StrRec,*StrCour,*StrPrec,*StrTemp; int p[2], /* pipe de communication */ pid, /* pid du fils */ stat, /* status du fils */ rc, /* Code de retour */ i,j; /* compteurs */ char ch; /* Tampon de lecture dans le pipe */ StrRec = (struct StrRec_s *)NULL; StrCour = (struct StrRec_s *)NULL; StrPrec = (struct StrRec_s *)NULL; StrTemp = (struct StrRec_s *)NULL; /* Ouvrir la fenetre qui fait patienter */ OpenWin(11,24,3,32,DoingNorm,SINGLE_FRAMED,SHADED); Printf(" Running ps %s...",PS_Cmd); fflush(stdout); /* Creation du pipe */ pipe(p); /* Creation du ss-process */ switch(pid = fork()) { case -1: CloseWin(); InitAnswerBoxItem(&InfoMsg); AddAnswerBoxItem(&InfoMsg,"ERROR: impossible to fork a child process"); InfoBox(ErrorNorm,ErrorInv," Processes ",InfoMsg,0,0,DOUBLE_FRAMED); return(-1); break; case 0: /* Processus fils: redirection de la sortie standard sur l'extremite 1 du pipe */ close(1); dup(p[1]); /* fermeture des deux extremites */ close(p[0]); close(p[1]); /* Execution du ps */ if(PS_Cmd[0] == 0) exit(execlp("ps","ps",NULL)); else exit(execlp("ps","ps",PS_Cmd,NULL)); break; default: /* Pere: fermeture de l'extremite 1 et attente de la fin du fils */ close(p[1]); wait(&stat); } /* Fermeture de la fenetre de patience */ CloseWin(); /* Boucle de lecture caractere par caractere dans le pipe. Chaque caractere lu est ajoute a une string temporaire. Des qu'un '\n' est recu, la string est terminee et enfilee dans la LLU */ i = 0; while(read(p[0],&ch,1) != 0) { DummyStr[i] = ch; if(ch == '\n') { DummyStr[i] = 0; StrTemp = (struct StrRec_s *)malloc(sizeof(struct StrRec_s)); if(StrTemp == (struct StrRec_s *)NULL) raise(SIGME); StrTemp->Str = (char *)malloc(strlen(DummyStr) + 2); if(StrTemp->Str == (char *)NULL) raise(SIGME); StrTemp->Suivant = (struct StrRec_s *)NULL; strcpy(StrTemp->Str,DummyStr); if(StrRec == (struct StrRec_s *)NULL) StrRec = StrTemp; else { StrCour = StrRec; StrPrec = (struct StrRec_s *)NULL; while(StrCour != (struct StrRec_s *)NULL) { StrPrec = StrCour; StrCour = StrCour->Suivant; } StrPrec->Suivant = StrTemp; } i = 0; } else i++; } /* Transmission terminee: fermer le pipe */ close(p[0]); /* Analyse des sorties ecran */ /* Elimination de la ligne de titre */ StrCour = StrRec; StrRec = StrRec->Suivant; free(StrCour->Str); free(StrCour); /* Initialisation du buffer de split */ for(i=0;iSuivant) { /* Splitter la ligne */ ConvertArgs(StrTemp->Str,Args,NB_ARGS); /* Analyser tous les composants par rapport au nom du programme */ for(i=0;iSuivant,ProcNbreEntries++) { ConvertArgs(StrCour->Str,Args,NB_ARGS); ProcTemp = (struct ProcRec_s *)malloc(sizeof(struct ProcRec_s)); if(ProcTemp == (struct ProcRec_s *)NULL) raise(SIGME); ProcTemp->Name = (char *)malloc(strlen(Args[NameCol]) + 1); if(ProcTemp->Name == (char *)NULL) raise(SIGME); ProcTemp->Term = (char *)malloc(strlen(Args[TermIDCol]) + 1); if(ProcTemp->Term == (char *)NULL) raise(SIGME); ProcTemp->Pid = (char *)malloc(strlen(Args[PidCol]) + 1); if(ProcTemp->Pid == (char *)NULL) raise(SIGME); strcpy(ProcTemp->Name,Args[NameCol]); strcpy(ProcTemp->Term,Args[TermIDCol]); strcpy(ProcTemp->Pid,Args[PidCol]); ProcTemp->Prec = (struct ProcRec_s *)NULL; if(strlen(ProcTemp->Name) < 28) strcpy(ProcTemp->Str,ProcTemp->Name); else { strcpy(ProcTemp->Str,"/..."); strcat(ProcTemp->Str,ProcTemp->Name + (strlen(ProcTemp->Name) - 23)); } for(i=strlen(ProcTemp->Str);i<33;i++) strcat(ProcTemp->Str," "); strcat(ProcTemp->Str,ProcTemp->Pid); for(i=strlen(ProcTemp->Str);i<45;i++) strcat(ProcTemp->Str," "); strcat(ProcTemp->Str,ProcTemp->Term); if(ProcRec == (struct ProcRec_s *)NULL) { ProcRec = ProcTemp; ProcRec->Suivant = (struct ProcRec_s *)NULL; } else { ProcTemp->Suivant = ProcRec; ProcRec->Prec = ProcTemp; ProcRec = ProcTemp; } for(i=0;iSuivant; free(StrPrec->Str); free(StrPrec); } return(rc); } /***************************************************************************** Processes() ------------------------------------------------------------------------------ Gestion des processus: fonction de presentation 1. Appel de la fonction de recherche 2. Presentation de la LLB constituee dans un ListBox un peu transforme. 3. Lors de l'entree de Enter, presentation d'un ListBox pour le choix du signal a envoyer. 4. Envoi du signal. 5. Boucle avec possibilite d'envoi d'autres signaux et relecture des process, et ce jusqu'a annulation. *****************************************************************************/ void Processes(void) { int Lig,Col, /* Coordonnees de la fenetre externe */ Height,Length, ActLig,ActCol, /* Coordonnees de la fenetre de liste */ ActHeight,ActLength, InvLig,InvCol, /* Coordonnees de la barre inverse */ i,j, /* Compteurs */ X,Y, /* Position du curseur */ SelIndex, /* Position dans la liste de process */ Sig, /* Signal a envoyer */ rc, /* Code de retour de la liste de signaux */ rc2, Fini = 0; /* Temoin de fin de boucle */ char Line[70]; /* Ligne de presentation */ ProcRec = (struct ProcRec_s *)NULL; ProcCour = (struct ProcRec_s *)NULL; ProcPrec = (struct ProcRec_s *)NULL; ProcTemp = (struct ProcRec_s *)NULL; ProcEnd = (struct ProcRec_s *)NULL; /* Recuperer la position du curseur */ GetXY(&Y,&X); /* Chercher les process */ if(ProcSystemOn) if(SearchForProcessWith_proc() == -1) return; else; else if(SearchForProcessWith_ps() == -1) return; else; /* Construire la fenetre d'affichage */ Line[0] = F_BDSD; for(i=1;i<53;i++) Line[i] = F_S_HO; Line[i] = F_SDBD; Line[i+1] = 0; Lig = 5; Col = 10; Height = 16; Length = 60; OpenWin(Lig,Col,Height,Length,ProcessNorm,UNFRAMED,SHADED); Lig += 1; Col += 3; Height -= 2; Length -= 6; PaintFrame(Lig,Col,Height,Length,ProcessNorm,DOUBLE_FRAMED); WriteString(" Processes ",ProcessNorm,6,35); WriteString(Line,ProcessNorm,8,13); WriteString(Line,ProcessNorm,16,13); WriteString(" NAME PID TTY", ProcessNorm,7,15); WriteString("Up/Down arrows to move, Enter to send a signal,", ProcessNorm,17,17); WriteString("Ctrl-R to refresh, Ctrl-C (Esc) to cancel.", ProcessNorm,18,20); ActLig = 9; ActCol = 14; ActLength = 52; ActHeight = 7; /* Initialiser le pointeur ProcEnd sur le dernier item de la liste */ for(ProcCurrent = ProcRec,ProcEnd = (struct ProcRec_s *)NULL; ProcCurrent != (struct ProcRec_s *)NULL; ProcEnd = ProcCurrent,ProcCurrent = ProcCurrent->Suivant); /* Afficher la portion superieure de la liste dans la fenetre */ for(i=ActLig,ProcCurrent = ProcRec; i < (ActLig + ActHeight) && ProcCurrent != (struct ProcRec_s *)NULL; i++,ProcCurrent = ProcCurrent->Suivant) WriteString(ProcCurrent->Str,ProcessNorm,i,ActCol+1); /* Fixer les coordonnees de la premiere zone d'invertion video */ InvLig = ActLig; InvCol = ActCol; /* Inverser la premiere option */ PaintString(InvLig,InvCol,ActLength,ProcessInv); /* Pour le moment, l'option choisie est la premiere de la liste */ ProcCurrent = ProcRec; SelIndex = 0; GotoXY(Y,X); fflush(stdout); while(!Fini) { switch(ReadKbd()) { case CR: switch(rc = ListBox(6,47,14,30,SignalsNorm,SignalsInv, " Choose signal ", Signals,LB_DOUBLE,DOUBLE_FRAMED)) { case 1: Sig = SIGTERM; break; case 2: Sig = SIGINT; break; case 3: Sig = SIGQUIT; break; case 4: Sig = SIGKILL; break; case 5: Sig = SIGHUP; break; case 6: Sig = SIGTRAP; break; case 7: Sig = SIGABRT; break; case 8: Sig = SIGUSR1; break; case 9: Sig = SIGUSR2; break; case 10: Sig = SIGALRM; break; } if(rc != -1) { if(kill(atoi(ProcCurrent->Pid),Sig) == 0) { InitAnswerBoxItem(&InfoMsg); sprintf(DummyStr,"Signal %d successfully sent to process",Sig); AddAnswerBoxItem(&InfoMsg,DummyStr); AddAnswerBoxItem(&InfoMsg,ProcCurrent->Name); InfoBox(OpOKNorm,OpOKInv," Kill ",InfoMsg,0,0,DOUBLE_FRAMED); } else { InitAnswerBoxItem(&InfoMsg); sprintf(DummyStr,"ERROR sending signal %d to process",Sig); AddAnswerBoxItem(&InfoMsg,DummyStr); AddAnswerBoxItem(&InfoMsg,ProcCurrent->Name); InfoBox(ErrorNorm,ErrorInv," Kill ",InfoMsg,0,0,DOUBLE_FRAMED); } } break; case CTRL_R: /* Effacer la liste courante */ ClrZone(ActLig,ActCol,ActHeight,ActLength,ProcessNorm); /* Liberer la liste de processes */ ProcCour = ProcRec; ProcPrec = (struct ProcRec_s *)NULL; while(ProcCour != (struct ProcRec_s *)NULL) { ProcPrec = ProcCour; ProcCour = ProcCour->Suivant; free(ProcPrec->Name); free(ProcPrec->Pid); free(ProcPrec->Term); free(ProcPrec); } ProcRec = (struct ProcRec_s *)NULL; if(ProcSystemOn) rc2 = SearchForProcessWith_proc(); else rc2 = SearchForProcessWith_ps(); if(rc2 == -1) { CloseWin(); Fini = 1; } else { /* Initialiser le pointeur ProcEnd sur le dernier item de la liste */ for(ProcCurrent = ProcRec,ProcEnd = (struct ProcRec_s *)NULL; ProcCurrent != (struct ProcRec_s *)NULL; ProcEnd = ProcCurrent,ProcCurrent = ProcCurrent->Suivant); /* Afficher la portion superieure de la liste dans la fenetre */ for(i=ActLig,ProcCurrent = ProcRec; i < (ActLig + ActHeight) && ProcCurrent != (struct ProcRec_s *)NULL; i++,ProcCurrent = ProcCurrent->Suivant) WriteString(ProcCurrent->Str,ProcessNorm,i,ActCol+1); /* Fixer les coordonnees de la premiere zone d'invertion video */ InvLig = ActLig; InvCol = ActCol; /* Inverser la premiere option */ PaintString(InvLig,InvCol,ActLength,ProcessInv); /* Pour le moment, l'option choisie est la premiere de la liste */ ProcCurrent = ProcRec; SelIndex = 0; GotoXY(Y,X); fflush(stdout); } break; case DELETE: case CTRL_C: case ESC: CloseWin(); Fini = 1; break; case K_UP: if(ProcCurrent->Prec != (struct ProcRec_s *)NULL) { /* Si le choix courant a un predecesseur, y deplacer la barre avec scrolling bas si necessaire */ SelIndex--; PaintString(InvLig,InvCol,ActLength,ProcessNorm); ProcCurrent = ProcCurrent->Prec; if(InvLig == ActLig) { ScrollDownWin(ActLig,ActCol,ActHeight,ActLength,1); WriteString(ProcCurrent->Str,ProcessNorm,ActLig,ActCol+1); } else InvLig--; PaintString(InvLig,InvCol,ActLength,ProcessInv); } break; case K_DOWN: /* Si le choix courant a un suivant, y deplacer la barre avec scrolling haut si necessaire */ if(ProcCurrent->Suivant != (struct ProcRec_s *)NULL) { SelIndex++; /* Si le choix courant a un suivant, y deplacer la barre avec scrolling haut si necessaire */ PaintString(InvLig,InvCol,ActLength,ProcessNorm); ProcCurrent = ProcCurrent->Suivant; if(InvLig == ActLig + ActHeight - 1) { ScrollUpWin(ActLig,ActCol,ActHeight,ActLength,1); WriteString(ProcCurrent->Str,ProcessNorm, ActLig+ActHeight-1,ActCol+1); } else InvLig++; PaintString(InvLig,InvCol,ActLength,ProcessInv); } break; case K_HOME: case CTRL_B: /* Si on est pas deja sur la premiere option, s'y deplacer, avec mise a jour de la porion de liste affichee si necessaire */ if(SelIndex != 0) { if(SelIndex < ActHeight && InvLig - SelIndex >= ActLig) /* L'item 0 est tjs dans la fenetre: simplement deplacer la barre */ PaintString(InvLig,InvCol,ActLength,ProcessNorm); else { /* L'item 0 n'est plus dans la fenetre: effacer tous les items et les reafficher a partir du 0, puis y placer la barre */ ClrZone(ActLig,ActCol,ActHeight,ActLength,ProcessNorm); for(i = ActLig,ProcCurrent = ProcRec; i < (ActLig + ActHeight) && ProcCurrent != (struct ProcRec_s *)NULL; i++,ProcCurrent = ProcCurrent->Suivant) WriteString(ProcCurrent->Str,ProcessNorm,i,ActCol+1); } ProcCurrent = ProcRec; SelIndex = 0; InvLig = ActLig; PaintString(InvLig,InvCol,ActLength,ProcessInv); } break; case K_END: case CTRL_E: /* Si on est pas sur la derniere option, s'y placer, avec mise a jour de la porion de liste affichee si necessaire */ if(SelIndex != ProcNbreEntries - 1) { if(InvLig + ProcNbreEntries - SelIndex <= ActLig + ActHeight) /* Le dernier item est deja dans la fenetre: simplement deplacer la barre */ PaintString(InvLig,InvCol,ActLength,ProcessNorm); else { /* Le dernier item n'est pas dans la fenetre: effacer tout et les reafficher pour avoir le dernier item en derniere position de la fenetre */ ClrZone(ActLig,ActCol,ActHeight,ActLength,ProcessNorm); /* Positionner ProcCurrent sur le premier item a devoir etre reaffiche en remontant la liste a partir de la fin */ for(i = 0,ProcCurrent = ProcEnd; i < ActHeight - 1 && ProcCurrent != (struct ProcRec_s *)NULL; i++,ProcCurrent = ProcCurrent->Prec); /* Affichage */ for(i = ActLig; i < (ActLig + ActHeight) && ProcCurrent != (struct ProcRec_s *)NULL; i++,ProcCurrent = ProcCurrent->Suivant) WriteString(ProcCurrent->Str,ProcessNorm,i,ActCol+1); } ProcCurrent = ProcEnd; SelIndex = ProcNbreEntries - 1; if(ProcNbreEntries < ActHeight) InvLig = ActLig + SelIndex; else InvLig = ActLig + ActHeight - 1; PaintString(InvLig,InvCol,ActLength,ProcessInv); } break; case CTRL_U: case K_PGUP: /* Si on est au milieu ou a la fin de la fenetre, remonter sur la premiere option Si on est au sommet de la fenetre, rectifier l'affichage vers le haut d'une fenetre moins un element. Si il ne reste pas assez d'elements pour faire ca, reafficher depuis le debut et placer la barre sur le premier element */ if(SelIndex != 0) { PaintString(InvLig,InvCol,ActLength,ProcessNorm); if(InvLig != ActLig) { /* La barre est au milieu de la fenetre: simplement la placer au sommet */ for(i=InvLig;i>ActLig;i--,ProcCurrent = ProcCurrent->Prec,SelIndex--); InvLig = ActLig; } else { /* La barre est deja au sommet: effacer tout et remonter dans la liste d'un nombre d'items egal a la hauteur de la fenetre. */ for(i = 0; i < ActHeight - 1 && ProcCurrent != (struct ProcRec_s *)NULL; i++,ProcCurrent = ProcCurrent->Prec,SelIndex--); /* Si ProcCurrent est a NULL, c'est que ce qui restait de la liste est plus petit qu'une hauteur de fenetre: on va donc reafficher depuis le debut */ if(ProcCurrent == (struct ProcRec_s *)NULL) { ProcCurrent = ProcRec; SelIndex = 0; } /* Affichage */ ProcTemp = ProcCurrent; ClrZone(ActLig,ActCol,ActHeight,ActLength,ProcessNorm); for(i = ActLig; i < (ActLig + ActHeight) && ProcTemp != (struct ProcRec_s *)NULL; i++,ProcTemp = ProcTemp->Suivant) WriteString(ProcTemp->Str,ProcessInv,i,ActCol+1); InvLig = ActLig; } PaintString(InvLig,InvCol,ActLength,ProcessInv); } break; case CTRL_D: case K_PGDN: /* Idem PgUp, mais vers le bas */ if(SelIndex != ProcNbreEntries - 1) { PaintString(InvLig,InvCol,ActLength,ProcessNorm); if(InvLig != ActLig + ActHeight - 1) { /* La barre est au milieu de la fenetre: simplement la placer a la fin */ if(ProcNbreEntries < ActHeight) { /* La liste est plus petite que la fenetre */ ProcCurrent = ProcEnd; InvLig = ActLig + ProcNbreEntries - 1; SelIndex = ProcNbreEntries - 1; } else { /* La liste est plus grande que la fenetre */ for(i=InvLig;i < ActLig + ActHeight - 1; i++,ProcCurrent = ProcCurrent->Suivant,SelIndex++); InvLig = ActLig + ActHeight - 1; } } else { /* La barre est deja a la fin: effacer tout et redescendre dans la liste d'un nombre d'items egal a la hauteur de la fenetre. - ProcTemp memorisera le premier item a etre reaffiche, c-a-d celui qui sera au sommet de la fenetre - ProcCurrent memorisera celui ou la barre en inverse se trouvera, dans ce cas, toujours sur la derniere ligne de la fenetre */ /* Donc, si il reste plus qu'une hauteur de fenetre dans la liste, lors d'un PGDN, l'item qui etait en inverse lorsque la barre est en fin de fenetre sera celui qui commencera les affichage a la fenetre suivante */ ProcTemp = ProcCurrent; /* Tester si il reste plus d'un fenetre a afficher */ for(i = 0; i < ActHeight - 1 && ProcCurrent != (struct ProcRec_s *)NULL; i++,ProcCurrent = ProcCurrent->Suivant,SelIndex++); /* Si ProcCurrent est a NULL, c'est que ce qui restait de la liste est plus petit qu'une hauteur de fenetre: on va donc reafficher une fenetre ayant le dernier item sur la derniere ligne */ if(ProcCurrent == (struct ProcRec_s *)NULL) { /* Positionner ProcTemp sur le premier item a devoir etre reaffiche en remontant la liste a partir de la fin. ProcCurrent sera dans ce cas toujour le dernier item de la liste */ for(i = 0,ProcCurrent = ProcEnd,ProcTemp = ProcEnd,SelIndex = ProcNbreEntries - 1; i < ActHeight - 1 && ProcTemp != (struct ProcRec_s *)NULL; i++,ProcTemp = ProcTemp->Prec); } /* Affichage */ ClrZone(ActLig,ActCol,ActHeight,ActLength,ProcessNorm); for(i = ActLig; i < (ActLig + ActHeight) && ProcTemp != (struct ProcRec_s *)NULL; i++,ProcTemp = ProcTemp->Suivant) WriteString(ProcTemp->Str,ProcessNorm,i,ActCol+1); InvLig = ActLig + ActHeight - 1; } PaintString(InvLig,InvCol,ActLength,ProcessInv); } break; } } CloseWin(); /* Liberer la liste de processes */ ProcCour = ProcRec; ProcPrec = (struct ProcRec_s *)NULL; while(ProcCour != (struct ProcRec_s *)NULL) { ProcPrec = ProcCour; ProcCour = ProcCour->Suivant; free(ProcPrec->Name); free(ProcPrec->Pid); free(ProcPrec->Term); free(ProcPrec); } ProcRec = (struct ProcRec_s *)NULL; }