MODULE nanotext; FROM Storage IMPORT ALLOCATE , DEALLOCATE; IMPORT Lib,Str,IO,Window,FIO; TYPE t_ptr_t_element = POINTER TO t_element; t_element = CLASS ptr_suivant : t_ptr_t_element; ptr_precedent : t_ptr_t_element; PROCEDURE affiche_element () ; VIRTUAL; BEGIN (* … impl‚menter par les objets fils *) END affiche_element; PROCEDURE detruit_element () ; VIRTUAL; BEGIN (* … impl‚menter par les objets fils *) END detruit_element; END; (* CLASS t_element *) TYPE t_liste = CLASS debut : t_ptr_t_element; ptr_courant : t_ptr_t_element; PROCEDURE creer() ; BEGIN debut := NIL; ptr_courant := NIL; END creer; PROCEDURE premier () : t_ptr_t_element ; BEGIN RETURN debut; END premier; PROCEDURE au_debut () ; (* d‚place le pointeur courant au d‚but de la liste *) BEGIN ptr_courant := debut; END au_debut; PROCEDURE suivant () : t_ptr_t_element; BEGIN RETURN ptr_courant^.ptr_suivant; END suivant; PROCEDURE a_la_fin (); (* d‚place le pointeur courant en queue de liste *) BEGIN WHILE suivant() <> NIL DO ptr_courant := ptr_courant^.ptr_suivant; END; END a_la_fin; PROCEDURE au_suivant (); (* d‚place le pointeur courant au paragraphe suivant si possible *) BEGIN IF suivant() <> NIL THEN ptr_courant := suivant(); END; END au_suivant; PROCEDURE precedent () : t_ptr_t_element; BEGIN RETURN ptr_courant^.ptr_precedent; END precedent; PROCEDURE au_precedent (); (* d‚place le pointeur courant au paragraphe precedent si possible *) BEGIN IF precedent() <> NIL THEN ptr_courant := precedent(); END; END au_precedent; PROCEDURE dernier ():t_ptr_t_element; BEGIN au_debut(); WHILE suivant() <> NIL DO au_suivant(); END; RETURN ptr_courant; END dernier; PROCEDURE liste_vide():BOOLEAN ; BEGIN RETURN debut = NIL; END liste_vide; PROCEDURE ajouter ( VAR y : t_element); VAR l_ptr_element : t_ptr_t_element; (* on ajoute en fin de liste : 2 cas : liste vide : liste non vide *) BEGIN ALLOCATE(l_ptr_element,SIZE(y)); Lib.Move(ADR(y),l_ptr_element,SIZE(y)); IF liste_vide() THEN (* cas du debut de liste vide *) debut := l_ptr_element; ptr_courant := l_ptr_element ; ptr_courant^.ptr_precedent := NIL; ptr_courant^.ptr_suivant := NIL; ELSE (* ajout en fin de liste *) l_ptr_element^.ptr_suivant := NIL; l_ptr_element^.ptr_precedent := ptr_courant; ptr_courant^.ptr_suivant := l_ptr_element; ptr_courant := l_ptr_element; END; END ajouter; PROCEDURE inserer (VAR y : t_element); (* On insŠre AVANT le pointeur courant !!!!!!!!! *) (* 2 cas : insertion en d‚but de liste insertion au milieu de liste *) VAR l_ptr_element : t_ptr_t_element; BEGIN ALLOCATE(l_ptr_element,SIZE(y)); Lib.Move(ADR(y),l_ptr_element,SIZE(y)); IF ptr_courant^.ptr_precedent = NIL THEN (* cas du d‚but de liste non vide *) debut := l_ptr_element; l_ptr_element^.ptr_precedent := NIL; l_ptr_element^.ptr_suivant := ptr_courant; ptr_courant^.ptr_precedent := l_ptr_element; ptr_courant := debut^.ptr_suivant; ELSE (* cas du milieu de liste *) ptr_courant^.ptr_precedent^.ptr_suivant := l_ptr_element; l_ptr_element^.ptr_suivant := ptr_courant; l_ptr_element^.ptr_precedent := ptr_courant^.ptr_precedent; ptr_courant^.ptr_precedent := l_ptr_element; ptr_courant := l_ptr_element^.ptr_suivant; END; (* IF *) END inserer; PROCEDURE inserer_liste ( VAR x : t_liste); BEGIN END inserer_liste; PROCEDURE detruire (); (* on detruit l'element du pointeur courant *) VAR l_ptr_element,ll_ptr_element : t_ptr_t_element; BEGIN ptr_courant^.detruit_element; IF ptr_courant^.ptr_precedent = NIL THEN (* cas du premier element de la liste **) (* 2 cas : liste compos‚e d'un element : liste composee de plusieurs elements *) IF ptr_courant^.ptr_suivant = NIL THEN DEALLOCATE(ptr_courant,SIZE(ptr_courant^)); debut := NIL; ptr_courant := NIL; ELSE ptr_courant := ptr_courant^.ptr_suivant; ptr_courant^.ptr_precedent := NIL; DEALLOCATE(debut,SIZE(debut^)); debut := ptr_courant; END; (* IF *) ELSIF ptr_courant^.ptr_suivant = NIL THEN (* cas d'un ‚l‚ment en fin de liste *) ptr_courant := ptr_courant^.ptr_precedent; DEALLOCATE(ptr_courant^.ptr_suivant,SIZE(ptr_courant^.ptr_suivant^)); ptr_courant^.ptr_suivant := NIL; ELSE (* cas g‚n‚ral d'un ‚l‚ment au milieu de liste *) l_ptr_element := ptr_courant^.ptr_suivant; l_ptr_element^.ptr_precedent := ptr_courant^.ptr_precedent; ptr_courant^.ptr_precedent^.ptr_suivant := l_ptr_element; DISPOSE(ptr_courant); ptr_courant := l_ptr_element; END ; (* IF *) END detruire; END; (* CLASS t_liste *) TYPE t_ptr_t_paragraphe = POINTER TO t_paragraphe; t_paragraphe = CLASS (t_element) longueur : CARDINAL; ptr_chaine : ADDRESS; nbre_lignes : CARDINAL; PROCEDURE initialise_element ( VAR x : ARRAY OF CHAR);VIRTUAL; BEGIN longueur := Str.Length(x); ALLOCATE(ptr_chaine,longueur); Lib.Move(ADR(x),ptr_chaine,longueur); END initialise_element; PROCEDURE affiche_element (); VIRTUAL; VAR l_tampon : ARRAY[0..1023] OF CHAR; BEGIN Lib.Move(ptr_chaine,ADR(l_tampon),longueur); l_tampon[longueur] := CHR(0); IO.WrStr(l_tampon); IO.WrLn; END affiche_element; PROCEDURE detruit_element () ; VIRTUAL; BEGIN DEALLOCATE(ptr_chaine,SIZE(ptr_chaine^)); END detruit_element; END; (* CLASS t_paragraphe *) TYPE t_fenetre = Window.WinDef; t_parametres = RECORD longueur_page : CARDINAL; largeur_ligne : CARDINAL; marge_haute : CARDINAL; marge_basse : CARDINAL; marge_droite : CARDINAL; marge_gauche : CARDINAL; largeur_tabulation : CARDINAL; entete : BOOLEAN; bas_de_page : BOOLEAN; END; TYPE t_ptr_t_tampon = POINTER TO t_tampon; TYPE t_ptr_t_texte = POINTER TO t_texte; t_texte = CLASS (t_liste) tampon : t_ptr_t_tampon; fenetre : Window.WinDef; parametres : t_parametres; ptr_fenetre : Window.WinType; curseurx : CARDINAL; curseury : CARDINAL; pos_fen_ds_txt : CARDINAL; PROCEDURE initialise_texte( VAR x : Window.WinDef; VAR y : t_parametres); BEGIN creer(); fenetre := x; parametres := y; ptr_fenetre := Window.Open(fenetre); END initialise_texte; PROCEDURE transfert_avant(); VIRTUAL; BEGIN END transfert_avant; PROCEDURE transfert_arriere(); VIRTUAL; BEGIN END transfert_arriere; PROCEDURE page_up(); VIRTUAL; BEGIN END page_up; PROCEDURE page_down(); VIRTUAL; BEGIN END page_down; PROCEDURE affiche_page(); VIRTUAL; BEGIN END affiche_page; END; (* CLASS t_texte *) (* le tampon est notre zone de travail : c'est dans lui que seront faites toutes les insertions et destructions , recherches ; donc le test des touches frapp‚es au clavier vont provoquer le transfert dans le tampon de notre paragraphe, et toutes les modifications se feront dans celui-ci; ceci nous procure en plus une fonction UNDO facile car le texte original n'est pas modifi‚ tant que le transfert inverse n'est pas r‚alis‚. Nous pourons sauvegarder toutes nos modifications dans une liste que nous pourrons ‚diter ou sauvegarder … souhait *) TYPE (* t_ptr_t_tampon = POINTER TO t_tampon;*) t_tampon = CLASS (t_paragraphe) position : CARDINAL; sauve_ptr_suivant : t_ptr_t_element; suve_ptr_precedent : t_ptr_t_element; la_liste : t_ptr_t_texte ; (* adresse de la liste *) PROCEDURE initialise_element ( VAR x : ARRAY OF CHAR ) ; VIRTUAL ; BEGIN (* notre tampon est un paragraphe particulier d'une taille de 32 Kilo-octets *) longueur := Str.Length(x); ALLOCATE(ptr_chaine,32*1024-1); Lib.Fill(ptr_chaine,32*1024-1,0); Lib.Move(ADR(x),ptr_chaine,longueur); END initialise_element; PROCEDURE init_adresse(VAR x : t_ptr_t_texte ); BEGIN la_liste := x; END init_adresse; PROCEDURE insere ( x : ARRAY OF CHAR ); VAR adresse1,adresse2 : ADDRESS; BEGIN adresse1 := Lib.AddAddr(ptr_chaine,position-1); IF position <= longueur THEN adresse2 := Lib.AddAddr(adresse1,Str.Length(x)); Lib.Move(adresse1,adresse2,longueur-position+1); INC(longueur,Str.Length(x)); Lib.Move(ADR(x),adresse1,Str.Length(x)); ELSE adresse2 := Lib.AddAddr(ptr_chaine,longueur); Lib.Move(ADR(x),adresse1,Str.Length(x)); Lib.Fill(adresse2,position-longueur-1,020H); longueur := position + Str.Length(x); END; END insere; PROCEDURE remplace ( x : ARRAY OF CHAR ); VAR adresse : ADDRESS; BEGIN adresse := Lib.AddAddr(ptr_chaine,position-1); Lib.Move(ADR(x),adresse,Str.Length(x)); END remplace; PROCEDURE detruit ( x : CARDINAL ); VAR adresse1,adresse2 : ADDRESS; BEGIN adresse1 := Lib.AddAddr(ptr_chaine,position + x - 1); adresse2 := Lib.AddAddr(ptr_chaine,position-1); Lib.Move(adresse1,adresse2,longueur-position); adresse1 := Lib.AddAddr(ptr_chaine,longueur); Lib.Fill(adresse1,x,0); DEC(longueur,x); END detruit; PROCEDURE affiche_element(); VIRTUAL ; (* le texte contenu dans notre paragraphe doit ˆtre justifi‚ *) (* on pourrait le justifier aprŠs coup, mais je pr‚fŠre une *) (* justification au fur … mesure *) TYPE l_ptr_tampon = POINTER TO l_t_tampon; l_t_tampon = ARRAY[0..32*1024-1] OF CHAR; VAR l_chaine : ARRAY[0..255] OF CHAR; i,j ,k : CARDINAL; mot : ARRAY[0..255] OF CHAR; (* chaque mot extrait de notre phrase *) separateur : ARRAY[0..255] OF CHAR; (* la chaŒne contenant les s‚parateurs initiaux qu'il faut conserver *) numero_mot : CARDINAL; (* le num‚ro du mot trait‚ *) num_mot_ds_ligne: CARDINAL; (* le numero du mot trait‚ dans la ligne *) nombre_blancs : CARDINAL; (* le nombre de blancs … r‚partie entre les mots *) longueur_phrase : CARDINAL; (* la longueur de notre phrase ne contenant que des mots entiers *) nombre_lignes : CARDINAL; sauve_position : CARDINAL; sauve_num_mot : CARDINAL; car : CHAR; BEGIN car := CHR(0); sauve_position := position; (* et on justifie le texte !!!!! *) mot := ""; separateur := ""; l_chaine := ""; numero_mot := 0; nombre_lignes := 0; num_mot_ds_ligne := 0; nombre_blancs := 0; mot := ""; separateur := ""; l_chaine := ""; longueur_phrase := 0; num_mot_ds_ligne:= 0; (* si premier caractŠre est un s‚parateur, il ne faut pas modifier la valeur de ce s‚parateur ( par exemple : une tabulation) On traite donc cette premiŠre ligne s‚par‚ment. Les lignes suivantes seront donc trait‚es toutes comme un premiŠre ligne ne commen‡ant pas par un s‚parateur. *) IF l_ptr_tampon(ptr_chaine)^[0] = CHR(32) THEN INC(nombre_lignes); LOOP (* on commence par faire les calculs pour une ligne *) Str.Item(separateur,l_ptr_tampon(ptr_chaine)^,Str.CHARSET{0C..CHAR(255)}-Str.CHARSET{" "},numero_mot); Str.Item(mot,l_ptr_tampon(ptr_chaine)^,Str.CHARSET{" "},numero_mot); IF mot[0] = CHR(0) THEN EXIT END; IF (longueur_phrase + Str.Length(separateur) + Str.Length(mot)) < la_liste^.parametres.largeur_ligne THEN INC(longueur_phrase ,Str.Length(separateur) + Str.Length(mot)); INC(numero_mot); INC(num_mot_ds_ligne) ELSE EXIT (* on ne peut plus mettre de mots dans la largeur impos‚e*) END; (* IF longu... *) END; (* LOOP *) (* calculs du nombre de blancs … ins‚rer *) nombre_blancs := la_liste^.parametres.largeur_ligne - longueur_phrase ; k :=num_mot_ds_ligne-1; (* et on construit notre texte justifi‚ *) Str.Item(separateur,l_ptr_tampon(ptr_chaine)^,Str.CHARSET{0C..CHAR(255)}-Str.CHARSET{" "},0); Str.Append(l_chaine,separateur); FOR i := numero_mot - num_mot_ds_ligne TO num_mot_ds_ligne - 2 DO Str.Item(separateur,l_ptr_tampon(ptr_chaine)^,Str.CHARSET{0C..CHAR(255)}-Str.CHARSET{" "},i+1); Str.Item(mot,l_ptr_tampon(ptr_chaine)^,Str.CHARSET{" "},i); Str.Append(l_chaine,mot); Str.Append(l_chaine,separateur); IF k >= 1 THEN FOR j := 1 TO nombre_blancs DIV k DO Str.Append(l_chaine," "); END; (* FOR *) END; (* IF *) DEC(nombre_blancs, nombre_blancs DIV k); DEC(k); END (* FOR *) ; Str.Item(mot,l_ptr_tampon(ptr_chaine)^,Str.CHARSET{" "},i+1); Str.Append(l_chaine,mot); position := 1 ; detruit(longueur_phrase); insere(l_chaine); (* et on traite les lignes suivantes ********) LOOP (* et on boucle jusqu'… la fin du paragraphe *) (* on remet … blanc nos variables de lignes ***) INC(nombre_lignes); num_mot_ds_ligne := 0; nombre_blancs := 0; mot := ""; separateur := ""; l_chaine := ""; longueur_phrase := 0; num_mot_ds_ligne:= 0; sauve_num_mot := numero_mot; LOOP (*calcul pour une ligne *) Str.Item(mot,l_ptr_tampon(ptr_chaine)^,Str.CHARSET{" "},numero_mot); IF mot[0] = CHR(0) THEN EXIT END; Str.Item(separateur,l_ptr_tampon(ptr_chaine)^,Str.CHARSET{0C..CHAR(255)}-Str.CHARSET{" "},numero_mot); IF (longueur_phrase + Str.Length(separateur) + Str.Length(mot)) < la_liste^.parametres.largeur_ligne THEN INC(longueur_phrase ,Str.Length(separateur) + Str.Length(mot)); INC(numero_mot); INC(num_mot_ds_ligne) ELSE DEC(longueur_phrase,Str.Length(separateur)); EXIT (* on ne peut plus mettre de mots dans la largeur impos‚e*) END; (* IF longu... *) END; (* LOOP *) (* calculs du nombre de blancs … ins‚rer *) nombre_blancs := la_liste^.parametres.largeur_ligne - longueur_phrase; IF num_mot_ds_ligne <1 THEN EXIT; END; k :=num_mot_ds_ligne-1; (* et on construit notre texte justifi‚ *) FOR i := sauve_num_mot TO sauve_num_mot + num_mot_ds_ligne - 2 DO Str.Item(mot,l_ptr_tampon(ptr_chaine)^,Str.CHARSET{" "},i); Str.Item(separateur,l_ptr_tampon(ptr_chaine)^,Str.CHARSET{0C..CHAR(255)}-Str.CHARSET{" "},i); Str.Append(l_chaine,mot); Str.Append(l_chaine,separateur); IF k >= 1 THEN FOR j := 1 TO nombre_blancs DIV k DO Str.Append(l_chaine," "); END; (* FOR *) END; (* IF *) DEC(nombre_blancs, nombre_blancs DIV k); DEC(k); END (* FOR *) ; Str.Item(mot,l_ptr_tampon(ptr_chaine)^,Str.CHARSET{" "},i+1); INC(numero_mot); Str.Append(l_chaine,mot); position := 1 + ((nombre_lignes-1) * la_liste^.parametres.largeur_ligne); detruit(longueur_phrase+1); insere(l_chaine); END; (* LOOP pour une ligne *) END; (* LOOP pour tout le reste du paragraphe *) position := 1 + ((nombre_lignes-1) * la_liste^.parametres.largeur_ligne) + longueur_phrase; insere(car); (* notre texte est maintenant justifi‚ *) i := 0; LOOP Str.Slice(l_chaine,l_ptr_tampon(ptr_chaine)^,i,la_liste^.parametres.largeur_ligne); (* affichage de la marge *) IF la_liste^.parametres.marge_gauche >= la_liste^.pos_fen_ds_txt THEN IO.WrCharRep(" ",la_liste^.parametres.marge_gauche - la_liste^.pos_fen_ds_txt) ; IO.WrStr(l_chaine); ELSE Str.Slice(l_chaine,l_chaine,la_liste^.pos_fen_ds_txt-la_liste^.parametres.marge_gauche, la_liste^.parametres.largeur_ligne - la_liste^.pos_fen_ds_txt); IO.WrStr(l_chaine); END; IO.WrCharRep(" ",la_liste^.parametres.marge_droite); IO.WrLn; IF Str.Length(l_chaine)< la_liste^.parametres.largeur_ligne THEN EXIT END; INC(i,30); END; position := sauve_position; END affiche_element; END; (* CLASS t_tampon *) TYPE t_ptr_t_paragraf= POINTER TO t_paragraf; t_paragraf = CLASS (t_paragraphe) la_liste : t_ptr_t_texte; (* adresse de la liste *) PROCEDURE init_adresse(VAR x : t_ptr_t_texte ); BEGIN la_liste := x; END init_adresse; PROCEDURE affiche_element(); VIRTUAL ; (*le texte contenu dans notre paragraphe est d‚j… justifi‚ *) TYPE l_ptr_tampon = POINTER TO l_t_tampon; l_t_tampon = ARRAY[0..32*1024-1] OF CHAR; VAR l_tampon : l_ptr_tampon; l_chaine : ARRAY[0..255] OF CHAR; i,j : CARDINAL; BEGIN NEW(l_tampon); Lib.Move(ptr_chaine,l_tampon,longueur); l_tampon^[longueur] := CHR(0); i := 0; LOOP Str.Slice(l_chaine,l_tampon^,i,la_liste^.parametres.largeur_ligne); (* affichage de la marge *) IF la_liste^.parametres.marge_gauche >= la_liste^.pos_fen_ds_txt THEN IO.WrCharRep(" ",la_liste^.parametres.marge_gauche - la_liste^.pos_fen_ds_txt) ; IO.WrStr(l_chaine); ELSE Str.Slice(l_chaine,l_chaine,la_liste^.pos_fen_ds_txt-la_liste^.parametres.marge_gauche, la_liste^.parametres.largeur_ligne - la_liste^.pos_fen_ds_txt); IO.WrStr(l_chaine); END; IO.WrCharRep(" ",la_liste^.parametres.marge_droite); IO.WrLn; IF Str.Length(l_chaine)< la_liste^.parametres.largeur_ligne THEN EXIT END; INC(i,30); END; DISPOSE(l_tampon); END affiche_element; END; (* class t_paragraf *) PROCEDURE attente; BEGIN REPEAT UNTIL IO.KeyPressed(); END attente; VAR mon_texte : t_texte; ptr_mon_texte : t_ptr_t_texte; el : t_paragraf; a : Window.WinDef; b : t_parametres; VAR fichier : FIO.File; buffer : ARRAY[0..10000] OF CHAR; car : CHAR; tt : t_tampon; PROCEDURE affiche; VAR g : t_ptr_t_paragraphe; BEGIN mon_texte.au_debut(); REPEAT mon_texte.ptr_courant^.affiche_element(); mon_texte.au_suivant(); UNTIL mon_texte.suivant() = NIL; mon_texte.ptr_courant^.affiche_element(); END affiche; PROCEDURE message (x : ARRAY OF CHAR); BEGIN Lib.Delay(5000); Window.Clear; IO.WrStr(x); IO.WrLn; END message; BEGIN (* principal *) WITH a DO X1 := 10; X2 := 65; Y1 := 1; Y2 := 25; Foreground := Window.Brown; Background := Window.Blue; CursorOn := TRUE; WrapOn := FALSE; Hidden := FALSE; FrameOn := TRUE; FrameDef := Window.DoubleFrame; FrameFore := Window.Blue; FrameBack := Window.Brown; END; WITH b DO longueur_page := 60; largeur_ligne := 40; marge_haute := 3; marge_basse := 3; marge_droite := 15; marge_gauche := 15; largeur_tabulation := 8; entete := TRUE; bas_de_page := TRUE; END; (************** CREATION DE LA LISTE ****************) mon_texte.initialise_texte(a,b); mon_texte.pos_fen_ds_txt := 20; ptr_mon_texte := ADR(mon_texte); (* (************** on remplit la liste *****************) message(" ON REMPLIT LA LISTE "); fichier := FIO.Open("c:\mii\mod.mod\texte1.MOD"); FIO.EOF := FALSE; FIO.RdStr(fichier,buffer); WHILE NOT FIO.EOF DO el.initialise_element(buffer); el.init_adresse(ptr_mon_texte); mon_texte.ajouter(el); FIO.RdStr(fichier,buffer); END; (************ on parcoure la liste en avant **********) message(" ON parcoure LA LISTE en avant"); affiche; *) buffer := " Bonjour messieurs-dames, il fait beau et nous pourrions bien aller bavarder quelque part dans la brousse ou la savane"; tt.initialise_element(buffer); tt.init_adresse(ptr_mon_texte); tt.affiche_element(); attente; message(" Fin du programme"); FIO.Close(fichier); END nanotext.