CTRLFIC

From Pickwiki
Revision as of 23:48, 26 February 2015 by Conversion script (talk) (link fix)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to navigationJump to search

To periodically check the Unidata files in level 1 overflow (from a list or just for given file) or level 2 using Unidata "guide" and "checkover" commands.

It creates a log in spool file _HOLD_ with Unidata commands you can execute later to optimize the found files. A mail is also send in case of corrupted files.

========= Main Program =============

*======================================================================
*= Domaine   : OUTILS
*= Programme : CTRLFIC
*= Version 7.1.1.1
*= Date de mise a jour : 01/09/25
*= Date de generation : 01/09/28
*======================================================================
*= L'instruction suivante permet de connaitre le numero de version du
*= programme compile sous unix par la commande : what _[[NomProgramme]]
*=
[[NumeroDeVersionDuProgramme]] = "@(#)[CTRLFIC 7.1.1.1 01/09/25]"
*=
*======================================================================
*-- Libelle : Controle de fichier
*-- Date creation : 18/08/97
*-- Reference : 
*-- Objet : Cf. c-dessous
*======================================================================
*-- Utilitaires

*-- Controle de la structure de fichiers Unidata par l'utilisation de
*-- la commande "guide"
*-- Le controle porte sur :
*--      Le fichier passe dans la commande s'il existe
*--      La liste active si l'on est en SELECT
*--      La liste LCTRLFIC si elle existe
*--      Rien si aucun des cas ci-dessus
*--
*-- Si l'execution se fait avec le parametre -M, la file SFILES<3> est
*-- automatiquement envoyee par mail a l'AU
*-- Creation : 18/08/97 par HME
*----------------------------------------------------------------------
*-- Modification : HME
*-- Le : 20/08/98
*-- Objet : Ajoût d'un SP.CLOSE de la file d'erreur avant de pouvoir
*--         la traiter par uuencode, sinon la piece jointe du mail
*--         est vide !
*----------------------------------------------------------------------
*-- Modification : HME
*-- Le : 10/03/99
*-- Objet : Rajout dans la file de messages des "conseils" donnes par
*--         la commande 'guide' afin d'optimiser les fichiers analyses.
*----------------------------------------------------------------------
*-- Modification : HME
*-- Le : 16/03/99
*-- Objet : Ajout, dans le cas d'un appel sans paramêtre, a un appel
*--         a l'utilitaire CHECKOVER qui recherche les fichiers du compte
*--         en debordement de niveau 2 afin de les ajouter a ceux de la
*--         liste LCTRLFIC
*----------------------------------------------------------------------
*----------------------------------------------------------------------
*-- Modification : HME
*-- Le : 13/01/00
*-- Objet : Ajout d'une trace d'execution dans le fichier BOITENOIRE
*----------------------------------------------------------------------
*----------------------------------------------------------------------
*-- Date de modification : 05/09/01
*-- Reference : DI00090, MDA_00090_001
*-- Objet : Ajouter la faculte de generer la liste des ordres d'optimisation des
*--	fichiers a executer apres le passage de CTRLFIC.
*--	Regeneration automatique de la liste LCTRLFIC (a partir de TT.CTRLFIC)
*--	si celle-ci a ete supprimee.
*--	Permettre a CTRLFIC de retourner un code d'erreur a la procedure
*--	appelante.
*----------------------------------------------------------------------
*
*=== Recuperation de l'ordre d'execution
PHRASE = @SENTENCE
PHRASE = TRIM(PHRASE)
*
*=== Initialisation de la trace d'execution
DATA "Controle des Fichiers",10
EXECUTE "TRACE.OLD"
CALL TRACE.DEBUT("CTRLFIC","Controle des Fichiers")
*
*=== Initialisation des files d'impression
SFILES = ''
SFILES<1> = ''
SFILES<2> = 'MES.CTRLFIC'
MESFILN = 1
SFILES<3> = 'ERR.CTRLFIC'
ERRFILN = 2
CALL SLIMPRIMANTE(SFILES)
GOSUB GETFILE ; *-- Recuperation du nom de la file d'erreurs dans _HOLD_
*
*=== Initialisation des variables
ERRFLAG =	0 ; *-- Nombre de fichiers errones
FICFLAG =	0 ; *-- Nombre de fichiers traites
ADVFLAG =	0 ; *-- Nombre de fichiers a optimiser.
NBFIC =		0 ; *-- Nombre de fichiers a traiter
NBUSR =		0 ; *-- Nombre d'utilisateurs Unidata
NFIC =		"" ; *-- Nom du fichier a traiter en parametre
FICHIER =	"" ; *-- Nom du fichier en cours de traitement
CAPUSR =	"" ; *-- Capture de l'execution de listuser
MFLAG =		"" ; *-- Flag de mail auto si pb
*-- Debut modification DI00090
EQUATE	TRUE TO 1, FALSE TO 0 ;	*-- Constantes booleenes
UNDEFINED =	"Indefini" ;	*-- Valeur introuvable dans EXTRAIRE
NL =		CHAR (10) ;	*-- Newline
POS =		0 ;	*-- Postition dans chaine ADVFIC pour recherche
FINI =		FALSE ;	*-- Condition de la boucle
CQFF =		'' ;	*-- Tableau avec Ce Qu'il Faut Faire (RESIZE, REBUILD)
[[NBL_CQFF]] =	0 ;	*-- Nombre de lignes dans CQFF
[[ERR_OK]] =	0 ;	*-- Pas d'erreur
[[ERR_VOC]] =	897 ;	*-- Fichier non trouve
[[ERR_FIXFILE]] =	998 ;	*-- Fichier doit être repare avec fixfile
[[ERR_KO]] =	999 ;	*-- Erreur grave
RC =		[[ERR_OK]];	*-- Code erreur
SORTIE.ECRAN =	"" ;	*-- Messages sur l'ecran
SORTIE.MSG =	"" ;	*-- Messages sur MESFILN1
SORTIE.ERR =	"" ;	*-- Messages sur ERRFILN1
[[ENTETE_MSG]] =	"" ;	*-- Entête des files MESFILN et ERRFILN
[[ENTETE_ERR]] =	"" ;	*-- Entête des files MESFILN et ERRFILN
[[PREDICTED_RESIZE_BLOCK_SIZE]] =	UNDEFINED
				*-- Valeur extraits d'ADVFIC dans EXTRAIRE
[[PREDICTED_RESIZE_MODULO]] =	UNDEFINED
				*-- Valeur extraits d'ADVFIC dans EXTRAIRE
[[CURRENT_BLOCK_SIZE]] =		UNDEFINED
				*-- Valeur extraits d'ADVFIC dans EXTRAIRE
[[BLOCK_SIZE_MULTIPLIER]] =		UNDEFINED
				*-- Parametre commande RESIZE
GOSUB ENTETE ;	*- Initialiser entêtes
RET1 =		"" ; 	*-- Resultat de RETURNING (non utilise)
CAP1 = 		"" ; 	*-- Resultat de CAPURING (non utilise)
*-- Fin modification DI00090
*=== Determination de la population a controler
*--- Recuperation du nom de fichier potentiel
IF FIELD(UPCASE(PHRASE)," ",1) # "RUN" THEN
	NFIC = FIELD(PHRASE," ",2)
	IF NFIC = "-M" THEN
		MFLAG = "-M"
		NFIC = ""
	END ELSE
		MFLAG = FIELD(PHRASE," ",3)
	END
END ELSE
	NFIC = FIELD(PHRASE," ",4)
	IF NFIC = "-M" THEN				
		MFLAG = "-M" 
		NFIC = ""
	END ELSE
		MFLAG=FIELD(PHRASE," ",5)
	END
END
*
IF NFIC <> "" ; *-- J'ai un nom en parametre de ma commande
THEN
	EXECUTE 'TSELECT VOC = "' : NFIC :'"' CAPTURING RESULTAT
	IF @SYSTEM.RETURN.CODE = 0 THEN
		*- Affichage message
		SORTIE.MSG := "Il n'y a pas de composant " : NFIC : NL
		SORTIE.MSG := NL
		SORTIE.MSG := "Pas de fichier selectionne, aucune analyse effectuee" : NL

		*- Affichage ecran
		SORTIE.ECRAN := "Il n'y a pas de composant " : NFIC : NL
		SORTIE.ECRAN := NL
		SORTIE.ECRAN := "Pas de fichier selectionne, aucune analyse effectuee" : NL
		FINI = TRUE
		*- N.B. Avec FINI = TRUE on n'entre pas dans la boucle
		GOSUB AFFICHAGE
	END
	IF @SYSTEM.RETURN.CODE < 0 THEN
		SORTIE.ECRAN := "Erreur lors selection dans VOC" : NL
		SORTIE.ECRAN := "Message d'erreur : ":RESULTAT : NL
		RC = [[ERR_KO]]
		*- N.B. Avec RC = [[ERR_KO]] on n'entre pas dans la boucle
		GOSUB AFFICHAGE
	END
	NBFIC = @SYSTEM.RETURN.CODE
END ELSE ; *-- Je n'ai pas de nom en parametre
	IF SELECTINFO(1) <> 1
	THEN ;	*-- Je ne suis pas dans une selection
		GOSUB CHKOVR ; *-- On va chercher les fichiers a optimiser
		IF RC # [[ERR_KO]] THEN
			GETLIST "LCTRLFICTOT" SETTING NBFIC ELSE
				SORTIE.MSG := "Pas de fichier selectionne, aucune analyse effectuee" : NL
				SORTIE.ECRAN := "Pas de fichier selectionne, aucune analyse effectuee" : NL
				FINI = TRUE
			END
		END
	END ELSE ; *-- Je suis dans une selection
		NBFIC = SYSTEM(11) ; *-- Je recupere le nombre d'elements de la liste
	END
END
GOSUB AFFICHAGE
*
SORTIE.MSG := "Il y a ":NBFIC:" fichier(s) a analyser" : NL
SORTIE.ECRAN := "Il y a ":NBFIC:" fichier(s) a analyser" : NL
*== Mise en garde sur les utilisateurs connectes
GOSUB GETUSR
*
*== On commence l'analyse de la population selectionnee
LOOP
	READNEXT FICHIER ELSE FINI = TRUE
	*
WHILE RC # [[ERR_KO]] AND NOT (FINI) DO ;*- Tant que RC # [[ERR_KO]] on continue
	FICFLAG = FICFLAG + 1
	IF FICHIER = "" OR FICHIER = "*" OR TRIM(FICHIER)=" " THEN CONTINUE
	*
	*- Verifier si FICHIER est de type DIR
	EXECUTE 'COUNT VOC "':FICHIER:'" IF F1 = "DIR"' RETURNING RET1 CAPTURING CAP1
	IF @SYSTEM.RETURN.CODE > 0 THEN ;*- Fichier de type DIR
		SORTIE.ECRAN := "Pas d'analyse de " : FICHIER : " (fichier de type DIR) " : NL
		SORTIE.MSG := "Pas d'analyse de " : FICHIER : " (fichier de type DIR) " : NL
		CONTINUE
		END	
	*- Verifier si FICHIER est un dictionnaire; DICT est affiche dans les
	*- commandes REBUILD ou RESIZE a executer
	DICT = ""
	IF FICHIER[1,2] = "D_" THEN DICT = "DICT " ; *- FICHIER est un dictionnaire
	*
	SORTIE.ECRAN := "Analyse de ":FICHIER:NL
	*- La suite sur MESFILN vient plus bas: Pas appeller AFFICHAGE
	SORTIE.MSG := TIMEDATE():" - Analyse de ":FICHIER
	*
	GOSUB GUIDE
	IF RC = [[ERR_KO]] THEN EXIT
	*
	FINDSTR "Errors encountered: 0" IN ERRFIC SETTING F,V,S THEN
		*
		*- Analyse fichier advice
		OSREAD ADVFIC FROM OSADVFIC ELSE NULL
		POS = INDEX (ADVFIC, "may improve performance", 1)
		IF POS <> 0 THEN
			*- La suite de Analyse de ...
			SORTIE.MSG := " - OK mais optimisation possible par " : NL
			SORTIE.MSG := ADVFIC : NL
			*
			*- Analyse approfondie
			GOSUB ANALYSE
			ADVFLAG = ADVFLAG + 1
		END ELSE
			SORTIE.MSG := " - OK" : NL ; *-- Pas de probleme pour ce fichier
		END
		GOSUB AFFICHAGE
		OSDELETE OSADVFIC
		OSDELETE OSFIXFIC
	END ELSE
		SORTIE.MSG := " - NOK" : NL ; *-- On a trouve au moins une erreur de structure
		GOSUB AFFICHAGE
		GOSUB FIXFILE
	END
	*
	*- Supprime fichier d'erreurs
	OSDELETE OSERRFIC
REPEAT ; *-- On va analyser un autre fichier
*
*=== Fin de programme, Affichage compte rendu
GOSUB [[COMPTE_RENDU]]
*
*=== MAJ de la trace d'execution
CALL TRACE.FIN("CTRLFIC","Controle des Fichiers")
IF NBFIC <> 0 THEN
	SORTIE.MSG := "======= FIN DES TRAITEMENTS =======" : NL
	GOSUB AFFICHAGE
END
*
*- Rendre Code Erreur a l'appelant
@USER.RETURN.CODE = RC
*
STOP "Fin de traitement (RC = " : RC : ")"
*
*===============================================================================
*
*=== Sous-programme pour la definition des entêtes
ENTETE:
	[[ENTETE_MSG]] = ""
	[[ENTETE_ERR]] = ""
	*
	[[ENTETE_MSG]] := "==============================================" : NL
	[[ENTETE_MSG]] := " ANALYSE DE LA STRUCTURE DES FICHIERS UNIDATA " : NL
	[[ENTETE_MSG]] := "==============================================" : NL
	[[ENTETE_ERR]] = [[ENTETE_MSG]]
	[[ENTETE_MSG]] := TIMEDATE() : CHAR(9) : "Programme : ":SYSTEM(40) : NL
	[[ENTETE_ERR]] := NL
	[[ENTETE_MSG]] := NL
	[[ENTETE_ERR]] := NL
	*
	RETURN
*
*=== Sous-programme pour l'affichagedes messages d'erreur
AFFICHAGE:
	*
	*- Affichage des 3 sorties
	IF SORTIE.MSG # "" THEN
		IF LEN ([[ENTETE_MSG]]) # 0 THEN
			PRINT ON MESFILN [[ENTETE_MSG]] [1, LEN ([[ENTETE_MSG]]) - 1]
			[[ENTETE_MSG]] = ""
		END
		PRINT ON MESFILN SORTIE.MSG [1, LEN (SORTIE.MSG) - 1]
		SORTIE.MSG = ""
	END
	*
	IF SORTIE.ERR # "" THEN
		IF LEN ([[ENTETE_ERR]]) # 0 THEN
			PRINT ON ERRFILN [[ENTETE_ERR]] [1, LEN ([[ENTETE_ERR]]) - 1]
			[[ENTETE_ERR]] = ""
		END
		PRINT ON ERRFILN SORTIE.ERR [1, LEN (SORTIE.ERR) - 1]
		SORTIE.ERR = ""
	END
	*
	IF SORTIE.ECRAN # "" THEN
		PRINT SORTIE.ECRAN [1, LEN (SORTIE.ECRAN) - 1]
		SORTIE.ECRAN = ""
	END
	*
	RETURN
*
*=== Sous-programme de recherche des utilisateurs connectes
GETUSR:
	IF (CAPUSR = "") THEN
		*- On appelle GETUSR deux fois, la deuxieme fois on sais
		*- deja combien il y en a d'utilisateurs, on affiche la mise en
		*- garde sur SORTIE.ERR
		PCPERFORM "listuser" CAPTURING CAPUSR
		*
		IF @SYSTEM.RETURN.CODE < 0 THEN
			NBUSR = -1 ; *-- listuser n'a pas fonctionne (peut-être pb proces lcp)
		END ELSE
			NBUSR = DCOUNT(CAPUSR,@AM) - 8 ; *-- On enleve l'entete, l'en-pied et nous
			CONVERT @AM TO NL IN CAPUSR
		END
		*
		*- Definir Mise en garde
		IF NBUSR > 1 THEN
			SORTIE.ECRAN := "!! Attention il y a d'autres utilisateurs connectes ce qui peut fausser les analyses !!" : NL
			[[MISE_EN_GARDE]] = NL
			[[MISE_EN_GARDE]] := "!! Attention il y a d'autres utilisateurs que vous (":@LOGNAME:"-":@USERNO:")" : NL
			[[MISE_EN_GARDE]] := "	ce qui peut fausser les analyses !!" : NL
			[[MISE_EN_GARDE]] := NL
		END ELSE
			IF NBUSR < 0 THEN
				SORTIE.ECRAN := "!! Impossible de controler la presence d'autres utilisateurs !!" : NL
				[[MISE_EN_GARDE]] := NL
				[[MISE_EN_GARDE]] := "!! Impossible de verifier la presence d'autres utilisateurs" : NL
				[[MISE_EN_GARDE]] := "	les analyses effectues devront donc etre controlees !!" : NL
				[[MISE_EN_GARDE]] := NL
			END
		END
		*- Mise en garde sortie sur MESFILN
		SORTIE.MSG := [[MISE_EN_GARDE]]
	END ELSE
		*- Mise en garde sortie sur ERRFILN
		SORTIE.ERR := [[MISE_EN_GARDE]]
		*- N.B. La partie SORTIE.ECRAN ne sort pas une deuxieme foix
	END
	*
	*- Afficher la mise en garde
	GOSUB AFFICHAGE
	*
	RETURN
*
*=== Sous-Programme de recuperation du nom de la file d'erreur
GETFILE:
*- Ce sous-programme suppose que la commande juste precedente est un
*- CALL SLIMPRIMANTE et que le dernier argument de ce dernier est la file
*- d'erreur.
	SOHOLD = 0 ; *-- Flag d'ouverture du dictionnaire de _HOLD_
	OPEN "DICT _HOLD_" TO FDHOLD ELSE SOHOLD = 1
	IF SOHOLD <> 1 THEN
		READV NUM FROM FDHOLD,"NEXT.HOLD",1 THEN
			NUM = NUM - 2 ; *-- on enleve 1 pour la file 19 de SLIMPRIMANTE et 1 pour avoir le dernier utilise
			ERRFIL = SFILES<3>:"_":NUM "R%4"
		END ELSE
			ERRFIL = SFILES<3>:"_????" ; *-- On n'a pas reussi a lire le dictionnaire, on prend tout !
		END
	END ELSE
		ERRFIL = SFILES<3>:"_????" ; *-- On n'a pas reussi a ouvrir le dictionnaire, on prend tout !
	END
	CLOSE FDHOLD
	RETURN
*
*=== Envoi d'un mail a l'AU
SENDMAIL:
	TMPFILE = "/tmp[[/CTRLFIC_]]":@USERNO:".sh" ; *-- Fichier temporaire de commande Unix
	TMPLINE="" ; *-- Tableau commandes Unix
	TMPLINE<1>="#!/sbin/sh"
	TMPLINE<2>="mail you@yourcompany <<ZZTABOULE"
	TMPLINE<3>="subject: ":ERRFIL
	TMPLINE<4>="L'analyse des fichiers par la commande ":PHRASE:" a produit la file jointe ":SFILES<3>
	TMPLINE<5>="Merci de verifier ces resultats et de corriger les fichiers dont la structure serait invalide"
	TMPLINE<6>=""
	TMPLINE<7>="Cette analyse a ete effectuee par le login ":@LOGNAME:" sur le compte ":@WHO
	TMPLINE<8>=""
	TMPLINE<9>="`uuencode ":OCONV("_HOLD_","TVOC;C;;2"):"/":ERRFIL:" ":ERRFIL:".doc`"
	TMPLINE<10>="ZZTABOULE"
	CONVERT @AM TO NL IN TMPLINE
	OSWRITE TMPLINE ON TMPFILE ON ERROR 
		GOSUB [[PB_MAIL]] ; *-- On cree le fichier de commande
		RETURN ; *-- Sortie de SENDMAIL
		END
	IF STATUS() <> 0 THEN 
		GOSUB [[PB_MAIL]]
		RETURN ; *-- Sortie de SENDMAIL
		END
	EXECUTE "! chmod u+wx ":TMPFILE:" ; ":TMPFILE:" ; rm ":TMPFILE ; *-- Et on l'execute avant de l'effacer
	IF @SYSTEM.RETURN.CODE < 0 THEN 
		GOSUB [[PB_MAIL]]
		RETURN ; *-- Sortie de SENDMAIL
		END
	*
	RETURN
*
[[PB_MAIL]]:
	*-- On a eu un probleme d'envoi de mail
	SORTIE.MSG := "Le mail n'a pas pu etre envoye a l'Assistance" : NL
	SORTIE.ECRAN := "Le mail n'a pas pu etre envoye a l'Assistance" : NL
	GOSUB AFFICHAGE
	*
	RETURN
*
*== Sous-programme de recuperation des overflow de niveau 2
CHKOVR:
	*- Ce sous-programme recupere les fichiers en overflow de type 2 et
	*- les ajoute a la liste LCTRLFIC pour faire la liste LCTRLFICTOT qui
	*- contient la totalite des fichiers a tester
	SORTIE.ECRAN := "Recherche des fichiers en debordement de niveau 2" : NL
	GOSUB AFFICHAGE
	*-
	*- On fait un peu de menage dans les listes
	EXECUTE "touch SAVEDLISTS[[/LCTRLFICOVR000]] ; touch SAVEDLISTS[[/LCTRLFICTOT000]]" CAPTURING RESULTAT
	*-
	*- On cherche les fichiers en overflow de type 2
	EXECUTE "! checkover" CAPTURING RESULTAT
	*-
	*- On recupere ces fichiers pour en faire une liste exploitable
	IF @SYSTEM.RETURN.CODE >= 0 THEN
	 	EXECUTE "! cat [[U_OVERFLOWED]] | awk '{print $1}' > SAVEDLISTS[[/LCTRLFICOVR000]]" CAPTURING RESULTAT
	 	EXECUTE "!wc -l SAVEDLISTS[[/LCTRLFICOVR000]] | awk '{print $1}'" CAPTURING RESULTAT
	 	SORTIE.ECRAN := "Il y a ":RESULTAT<1,1>:" fichier(s) en debordement de niveau 2" : NL
	END
	IF @SYSTEM.RETURN.CODE >= 0 THEN EXECUTE "rm [[U_OVERFLOWED]]" CAPTURING RESULTAT
	*-
	*- Verifier existence LCTRLFIC
	*- Si elle n'existe plus on va la creer avec LCTRLFIC
	PHRASE = 'SELECT SAVEDLISTS ="LCTRLFIC000"'
	EXECUTE PHRASE CAPTURING RESULTAT
	TROUVE = @SYSTEM.RETURN.CODE
	*- Ne pas oublier : dans LCTRLFIC il y a un autre SELECT
	CLEARSELECT
	IF TROUVE = 0 THEN
		SORTIE.ECRAN := "Reconstitution de la liste des fichiers a verifier" : NL
		GOSUB LCTRLFIC
	END
	*-
	*- On reunit les listes LCTRLFIC et LCTRLFICOVR dans LCTRLFICTOT
	DATA "LCTRLFICTOT"
	EXECUTE "SLUNION-LIST SAVEDLISTS LCTRLFIC LCTRLFICOVR" CAPTURING RESULTAT
	*-
	IF @SYSTEM.RETURN.CODE < 0 THEN
		SORTIE.ECRAN := "Erreur SLUNION-LIST":NL
		SORTIE.ECRAN := "Message d'erreur : ":RESULTAT : NL
		RC = [[ERR_KO]]
		*
		RETURN
	END
	*
	RETURN
*
*== Sous-programme pour la reconstitution de la liste LCTRLFIC si celle-ci a ete
*== supprimee
LCTRLFIC:
	*- Lire le fichier TT.CTRLFIC
	OPEN 'TT.CTRLFIC' TO TT.CTRLFIC ELSE
		SORTIE.ECRAN := "Erreur lors de l'ouverture TT.CTRLFIC" : NL
		RC = [[ERR_KO]]
		*
		RETURN
	END
	SELECT TT.CTRLFIC
	*- Lire la liste LCTRLFIC000 dans TT.CTRLFIC.REC
	READ TT.CTRLFIC.REC FROM TT.CTRLFIC,"LCTRLFIC000" ELSE
		SORTIE.ECRAN := "Erreur de lecture TT.CTRLFIC" : NL
		RC = [[ERR_KO]]
		*
		RETURN
	END
	*
	CLOSE TT.CTRLFIC
	*- Sauve la liste dans LCTRLFIC car SLUNION-LIST attend les 2 listes dans
	*- SAVEDLISTS
	*- La phrase "... key(s) written to 1 record." apparait a l'ecran
	WRITELIST TT.CTRLFIC.REC ON "LCTRLFIC"
	CLEARSELECT
	*
	RETURN
*
*== Sous-programme d'extraction de parametres pour RESIZE
EXTRAIRE:
	*- Recuperer
	*-	"current block size",
	*-	"predicted resize block size" et
	*-	"predicted resize modulo".
	*- ADVFIC contient les lignes suivantes (y compris les blancs en debut
	*- de ligne):
	************************************************
	*       The average data size of 129.57 bytes,
	*    the standard deviation of 12.30 bytes,
	*    and the total data size of 534367 bytes
	*    were evaluated.  The predicted resize
	*    block size is 2048 bytes.  The predicted
	*    resize modulo is 379 group(s).
	*    The current block size is 1024 bytes.
	*    The current modulo is 11 group(s).
	************************************************
	* Il y a une variante :
	*    were evaluated.  The predicted resize
	*    values are the same as the current ones.
	*    Changing the modulo may help.

	* Dans ce cas ce qu'il faut faire est un RESIZE sans arguments
	************************************************
	*
	*- Initialisation des variables a indefini
	[[PREDICTED_RESIZE_BLOCK_SIZE]] = UNDEFINED
	[[PREDICTED_RESIZE_MODULO]] = UNDEFINED
	[[CURRENT_BLOCK_SIZE]] = UNDEFINED
	*- Les 4 chaines que l'on va chercher
	LOOK<1> = "The predicted resize"
	LOOK<2> = "block size is "
	LOOK<3> = "resize modulo is "
	LOOK<4> = "The current block size is "
	LOOK<9> = "values are the same as the current ones"
	*
	FOR I = 1 TO 4 ;*- Pas 9 !!!
		POS = INDEX (ADVFIC [1, LEN (ADVFIC)], LOOK <I>, 1)
		IF (POS = 0) THEN
			IF (I = 2 AND INDEX (ADVFIC [1, LEN (ADVFIC)], LOOK <9>, 1) = 1) THEN
				*- Dans ce cas il faut faire RESIZE sans
				*- arguments. Remonte dans ASS28819
				*- Il se peut qu'apres le RESIZE guide donnne
				*- les même conseils
				*
				RETURN
			END
			*
			SORTIE.ECRAN := "Erreur inattendue" : NL
			SORTIE.ECRAN := CHAR(9) : LOOK <I> : " introuvable" : NL
			RC = [[ERR_KO]]
			*
			RETURN
		END
		*
		*- ADVFIC advance
		BEGIN CASE
			CASE I = 1
				*- 4 blanc en debut de ligne plus un <NL>
				*- N.B.
				*- ADVFIC [POS + LEN (LOOK) + 5, LEN (ADVFIC)]
				*- n'est pas la même chose que
				*- ADVFIC = ADVFIC [POS + LEN (LOOK) + 5]
				ADVFIC = ADVFIC [POS + LEN (LOOK<I>) + 5, LEN (ADVFIC)]
			CASE I <> 1
				ADVFIC = ADVFIC [POS + LEN (LOOK<I>), LEN (ADVFIC)]
		END CASE
		*
		*- Extraire les valeurs necessaires
		BEGIN CASE
			CASE I = 2
				*- Catch "predicted resize block size"
				[[PREDICTED_RESIZE_BLOCK_SIZE]] = FIELD (ADVFIC, " ", 1)
			CASE I = 3
				*- Catch "predicted resize modulo"
				[[PREDICTED_RESIZE_MODULO]] = FIELD (ADVFIC, " ", 1)
			CASE I = 4
				*- Catch "current block size"
				[[CURRENT_BLOCK_SIZE]] = FIELD (ADVFIC, " ", 1)
		END CASE
	NEXT I
	*
	*- [[UniData]] Commands Reference
	*- block.size.multiplier
	*-	An integer between 0 and 16, that determines block size:
	*-	0	512 bytes
	*-	1	1,024 bytes
	*-	2	2,048 bytes
	*-	4	4,096 bytes
	*-	8	8,192 bytes
	*-	16 or greater
	*-		16 bytes
	*- Pour "16 bytes" j'ai lu "16 kbytes"
	BEGIN CASE
	CASE [[PREDICTED_RESIZE_BLOCK_SIZE]] < 1024
		[[BLOCK_SIZE_MULTIPLIER]] = 0
	CASE [[PREDICTED_RESIZE_BLOCK_SIZE]] > 8192
		[[BLOCK_SIZE_MULTIPLIER]] = 16
	CASE [[PREDICTED_RESIZE_BLOCK_SIZE]] = UNDEFINED
		[[BLOCK_SIZE_MULTIPLIER]] = UNDEFINED
	CASE TRUE
		*- Calcul de base, voir tableau ci-dessus
		[[BLOCK_SIZE_MULTIPLIER]] = [[PREDICTED_RESIZE_BLOCK_SIZE]] / 1024
	END CASE
	*
	RETURN
*
*== Sous-programme pour execution de la commande guide
GUIDE:
	OSERRFIC = '/tmp[[/CTRLFIC_]]':FICHIER:'.LIS'
	OSDELETE OSERRFIC
	OSFIXFIC = '/tmp[[/CTRLFIC_]]':FICHIER:'.DAT'
	OSDELETE OSFIXFIC
	OSADVFIC = '/tmp[[/CTRLFIC_]]':FICHIER:'.ADV'
	OSDELETE OSADVFIC
	COMMAND = '! guide -ns -a':OSADVFIC:' -e':OSERRFIC:' -f':OSFIXFIC:' "':FICHIER:'"'
	*-
	*-- Debut modification DI00090
	*- Ajoute CAPTURING RESULTAT car des messages suivants apparaissent lors
	*- de l'execution de guide
	*-	one "*" represents 2000 groups
	*-	**
	EXECUTE COMMAND CAPTURING RESULTAT
	*-- Fin modification DI00090
	*-
	IF @SYSTEM.RETURN.CODE < 0 THEN
		SORTIE.ECRAN := "Erreur lors de l'execution de : guide":NL
		SORTIE.ECRAN := "Message d'erreur : ":RESULTAT : NL
		RC = [[ERR_KO]]
		GOSUB AFFICHAGE
	END
	OSREAD ERRFIC FROM OSERRFIC ELSE
		SORTIE.ECRAN := "Pb lecture resultat de guide":NL
		SORTIE.ECRAN := "Message d'erreur : ":RESULTAT : NL
		RC = [[ERR_KO]]
		GOSUB AFFICHAGE
	END
	*
	RETURN
*
*== Sous-programme pour l'analyse du fichier OSADVDIC contenant des consignes
*== pour optimiser FICHIER
ANALYSE:
	*- Analyse ADVFIC
	*
	*- Est-ce qu'il s'agit d'un RESIZE ou d'un REBUILD ?
	*- Qu'est-ce qu'il y avait avant "may improve
	*- performance" ?
	LOOK = "Resizing this file "
	*- Chercher LOOK a partir de POS moins la longeuer de
	*- LOOK, on doit tomber a 1
	*- N.B. INDEX sur une chaine sans fin ne marche pas!
	*- "INDEX (ADVFIC [POS - LEN(LOOK) - 1], LOOK, 1) = 0"
	IF INDEX (ADVFIC [POS - LEN(LOOK), LEN (ADVFIC)], LOOK, 1) = 1
	THEN
		*- Il s'agit de: "Resizing this file may improve
		*- performance"
		*- ATTENTION Il ne faut plus ce servir de ADVFIC
		*- apres EXTRAIRE et ceci jusqu'a la prochaine boucle
		ADVFIC = ADVFIC [POS - LEN(LOOK) - 1, LEN (ADVFIC)]
		*
		*- Extraire les valeurs pour la commande RESIZE
		GOSUB EXTRAIRE
		IF RC = [[ERR_KO]] THEN RETURN
		*
		*- Ce Qu'il Faut Faire
		IF [[PREDICTED_RESIZE_BLOCK_SIZE]] = UNDEFINED OR [[PREDICTED_RESIZE_MODULO]] = UNDEFINED OR [[CURRENT_BLOCK_SIZE]] = UNDEFINED THEN
			*- Pas de preconisations trouvees
			[[NBL_CQFF]] += 1
			CQFF <NBL_CQFF> = "RESIZE ":DICT:FICHIER
		END ELSE
			IF [[PREDICTED_RESIZE_BLOCK_SIZE]] = [[CURRENT_BLOCK_SIZE]] THEN
				*- Pas besoin de redimensionner
				*- le [[BLOCK_SIZE]]
				[[NBL_CQFF]] += 1
				CQFF <NBL_CQFF> = "RESIZE " : DICT : FICHIER : " " : [[PREDICTED_RESIZE_MODULO]]
			END ELSE
				*- Redimensionner le [[BLOCK_SIZE]]
				[[NBL_CQFF]] += 1
				CQFF <NBL_CQFF> = "RESIZE " : DICT : FICHIER : " " : [[PREDICTED_RESIZE_MODULO]] : "," : [[BLOCK_SIZE_MULTIPLIER]]
			END
		END
	END ELSE
		*- Pareil que pour "Resizing this file ..." ci-dessus
		LOOK = "Running REBUILD.FILE "
		IF INDEX (ADVFIC [POS - LEN(LOOK), LEN (ADVFIC)], LOOK, 1) = 1
		THEN
			[[NBL_CQFF]] += 1
			CQFF <NBL_CQFF> = "REBUILD.FILE ":DICT:FICHIER
		END ELSE
			*- On a trouve "may improve performance"
			*- mais on n'a pas reconnu ce qu'il y a
			*- avant
			SORTIE.ECRAN := "Erreur inattendue" : NL
			RC = [[ERR_KO]]
			GOSUB AFFICHAGE
			*
			RETURN
		END
	END
	*
	RETURN
*
*== Sous programme pour message d'erreur dans file d'erreur
FIXFILE:
	IF ERRFLAG = 0
	THEN ;	*- Deuxieme appel de GETUSR, affiche sur ERRFILN (l'entête y
		*- sera egalement initialise)
		*- On sais deja combien il y a d'utilisateurs mais on affiche la
		*- mise en garde a nouveau
		GOSUB GETUSR
	END
	*
	ERRFLAG = ERRFLAG + 1
	SORTIE.ERR := "====================================================================" : NL
	SORTIE.ERR := TIMEDATE(): NL
	SORTIE.ERR := "Erreur(s) detectee(s) lors du controle du fichier ":FICHIER: NL
	SORTIE.ERR := ERRFIC: NL
	*
	FINDSTR "No files were processed!" IN ERRFIC SETTING F,V,S THEN
		SORTIE.ECRAN := "Fichier ":FICHIER:" a analyser mais physiquement introuvable" : NL
		RC = [[ERR_VOC]]
	END ELSE
		SORTIE.ERR := "Le fichier ":OSFIXFIC:" devrait aider a reparer le fichier ":FICHIER:"." : NL
		SORTIE.ERR := "Apres avoir sauvegarde le fichier ":FICHIER:" et s'etre assure que" : NL
		SORTIE.ERR := "personne n'y accede, on pourra utiliser la commande" : NL

		SORTIE.ERR := "fixfile -f -d/tmp[[/RECUP_]]":FICHIER:" -i":OSFIXFIC : NL
		SORTIE.ERR := "====================================================================" : NL
		SORTIE.ECRAN := " Des erreurs ont ete trouvees pour le fichier ":FICHIER : NL
		SORTIE.ECRAN := " Contacter l'Assistance " : NL
		SORTIE.ECRAN := " lui fournissant la file ":SFILES<3> : NL
		RC = [[ERR_FIXFILE]]
	END
	*
	GOSUB AFFICHAGE
	*
	RETURN
*
*== Sous-programme de compte-rendu de CTRLFIC
[[COMPTE_RENDU]]:
	IF RC = [[ERR_KO]] THEN
		IF FICHIER <> "" THEN SORTIE.ECRAN := "Erreur lors de l'analyse du fichier ":FICHIER : NL
		SORTIE.ECRAN := "Contacter l'Assistance" : NL
		SORTIE.ECRAN := "avec le message d'erreur ci-dessus" : NL
	END
	*
	IF NBFIC <> 0 THEN
		SORTIE.MSG := NL
		SORTIE.MSG := TIMEDATE():" Il y a eu ":ERRFLAG:" fichier(s) errone(s), ":ADVFLAG:" optimisable(s), sur ":FICFLAG:" controle(s)" : NL
	END
	*
	IF ERRFLAG <> 0 THEN
		SORTIE.MSG := " Contacter l'Assistance" : NL
		SORTIE.MSG := " lui fournissant la file ":SFILES<3> : NL
		SORTIE.ERR := NL
		SORTIE.ERR := TIMEDATE():" Il y a eu ":ERRFLAG:" fichier(s) errone(s), ":ADVFLAG:" optimisable(s), sur ":FICFLAG:" controle(s)" : NL
		SORTIE.ERR := "======= FIN DES TRAITEMENTS =======" : NL
		EXECUTE "SP.CLOSE ":ERRFILN
		IF (MFLAG = "-M" OR MFLAG = "M") THEN GOSUB SENDMAIL ; *-- Envoi d'un mail 
	END
	*
	*- Ce Qu'il Faut Faire
	IF [[NBL_CQFF]] > 0 THEN
		SORTIE.MSG := NL
		SORTIE.MSG := "Pour optimiser les performances executer les commandes suivantes :" : NL
		FOR I = 1 TO [[NBL_CQFF]]
			SORTIE.MSG := CQFF <I> : NL
		NEXT I
	END
	*
	*- Dernier affichage
	GOSUB AFFICHAGE
	*
	RETURN

========= Subroutines =============

*==========================================================================
*= Programme : SLUNION-LIST
*= Version 1.1
*= Date de mise à jour : 96/04/25
*= Date de génération : 01/02/14
*===========================================================================
*= L'instruction suivante permet de connaître le numéro de version du       
*= programme compilé sous unix par la commande : what _[[NomProgramme]]         
*=                                                                          
[[NumeroDeVersionDuProgramme]] = "@(#)[SLUNION-LIST 1.1 96/04/25]"                      
*=                                                                          
*===========================================================================
*----------------------------------------------------------------------------
*-- PORTAGE
*-- ESD : Remplace LIST.UNION pour les Procs
*-- Creation : 11:04:13  06 Dec 1994  
*-- Version : 1.0
*-- Date de MAJ :
*-- MAJ :
*-- Compile  : 
*----------------------------------------------------------------------------
* ATTENTION : 
*     . le programme se compile en type 'U'
*     . le programme se met en type UNIDATA pour utiliser MERGE-LIST
*----------------------------------------------------------------------------
* Differences entre ESD et UNIDATA
*     . la syntaxe generale est differente
*     . les listes peuvent se trouver dans un fichier autre que POINTER-FILE
*----------------------------------------------------------------------------
*  SYNTAXE :  SLUNION-LIST nom.fichier list1 list2
*  =======    TO : {(nnom.fichier} list3
*     . nom.fichier : nom du fichier ou sont stockees les listes
*     . list1 : premiere liste
*     . list2 : seconde liste
*     . nnom.fichier : nom du fichier ou ecrire la liste resultat
*         si pas de nom de fichier alors c'est celui de depart
*     . list3 : liste resultat
*----------------------------------------------------------------------------
* ATTENTION : si le fichier n'est pas SAVEDLISTS
*     . copie des listes dans le fichier SAVEDLISTS
*     . execution de la commande MERGE-LIST de UNIDATA
*     . recopie de la liste resulat dans le bon fichier
*     . suppression des listes dans SAVEDLISTS
*----------------------------------------------------------------------------
* Initialisation des variables
*
    PROMPT ""
* Liste des messages d'anomalies
    LMSG    = ""
    LMSG<1> = "0":@VM:"Impossible d'ouvrir le fichier --> "
*
    OPEN "SAVEDLISTS" TO FLIS ELSE
      NOMSG = 1 ; MSGC = "SAVEDLISTS" ; GOSUB 9999
    END
*----------------------------------------------------------------------------
* Lecture , analyse et reconstitution des donnees de depart
*
    PHRASEDEP = @SENTENCE
    PHRASEDEP = TRIM(PHRASEDEP)
* Nom du fichier
    DNOMFIC = FIELD(PHRASEDEP," ",2)
    LISTE1  = FIELD(PHRASEDEP," ",3)
    LISTE2  = FIELD(PHRASEDEP," ",4)
    OPTION  = FIELD(PHRASEDEP," ",5)
* si le fichier n'est pas SAVEDLIST alors copier les listes 
*   dans le fichier SAVEDLISTS, exec
    IF DNOMFIC # "SAVEDLISTS" THEN
      ITLIS1 = "$":LISTE1:"$"
      ITLIS2 = "$":LISTE2:"$"
      OPEN DNOMFIC TO FDEP ELSE NOMSG = 1 ; MSGC = DNOMFIC ; GOSUB 9999
      READ WDEP FROM FDEP,LISTE1 ELSE WDEP = ""
      READU EXIST FROM FLIS,ITLIS1:"000" ELSE NULL
      WRITE WDEP ON FLIS,ITLIS1:"000"
      READ WDEP FROM FDEP,LISTE2 ELSE WDEP = ""
      READU EXIST FROM FLIS,ITLIS2:"000" ELSE NULL
      WRITE WDEP ON FLIS,ITLIS2:"000"
    END ELSE
      ITLIS1 = LISTE1
      ITLIS2 = LISTE2
    END
*----------------------------------------------------------------------------
* Lecture des donnees d'arrivee
*
    INPUT PHRASEARR:
    PHRASEARR = TRIM(PHRASEARR)
    IF PHRASEARR[1,1] = "(" THEN
      ANOMFIC = FIELD(PHRASEARR," ",1)
      ANOMFIC = ANOMFIC[2,LEN(ANOMFIC)-1]
      LISTE3  = FIELD(PHRASEARR," ",2)
    END ELSE
      ANOMFIC = DNOMFIC
      LISTE3  = FIELD(PHRASEARR," ",1)
    END
    IF ANOMFIC # "SAVEDLISTS" THEN
      ITLIS3 = "$":LISTE3:"$"
      OPEN ANOMFIC TO FARR ELSE NOMSG = 1 ; MSGC = ANOMFIC ; GOSUB 9999
    END ELSE
      ITLIS3 = LISTE3
    END
*----------------------------------------------------------------------------
* Appel de MERGE-LIST de UNIDATA --> se mettre en type UNIDATA
*
    EXECUTE "GET.LIST ":ITLIS1:" TO 1"
    EXECUTE "GET.LIST ":ITLIS2:" TO 2"
    EXECUTE "MERGE.LIST 1 UNION 2 TO 3"
    EXECUTE "SAVE.LIST ":ITLIS3:" FROM 3"
*----------------------------------------------------------------------------
* Suppression des lignes a vides dans SAVEDLISTS
*
    READU WARR FROM FLIS,ITLIS3:"000" ELSE WARR = ""
    IFIN = DCOUNT(WARR,@AM)
    I = 1
10  IF I > IFIN THEN GO 20
    IF WARR<I> = "" THEN
      WARR = DELETE(WARR,I) ; IFIN = IFIN - 1
    END ELSE
      I = I + 1
    END
    GO 10
20  WRITE WARR ON FLIS,ITLIS3:"000"
*----------------------------------------------------------------------------
* Si le fichier resultat # SAVEDLIST, mise a jour de la liste resultat
*
    IF ANOMFIC # "SAVEDLISTS" THEN
      READU WARR FROM FLIS,ITLIS3:"000" ELSE WARR = ""
      READU EXIST FROM FARR,LISTE3 ELSE NULL
      IF WARR = "" THEN
        DELETE FARR,LISTE3
      END ELSE
        WRITE WARR ON FARR,LISTE3
      END
      DELETE FLIS,ITLIS3:"000"
    END ELSE
      READU WARR FROM FLIS,ITLIS3:"000" ELSE WARR = ""
      IF WARR = "" THEN
        DELETE FLIS,ITLIS3:"000"
      END ELSE
        RELEASE FLIS,ITLIS3:"000"
      END
    END
*----------------------------------------------------------------------------
* Si le fichier de depart # SAVEDLIST, mise a jour de SAVEDLISTS
*
    IF DNOMFIC # "SAVEDLISTS" THEN
      READU EXIST FROM FLIS,ITLIS1:"000" ELSE NULL
      DELETE FLIS,ITLIS1:"000"
      READU EXIST FROM FLIS,ITLIS2:"000" ELSE NULL
      DELETE FLIS,ITLIS2:"000"
    END
*----------------------------------------------------------------------------
99  STOP
*----------------------------------------------------------------------------
9999 PRINT
     PRINT "[ ":NOMSG:" ]  ":LMSG<NOMSG,2>:MSGC
     PRINT
     IF LMSG<NOMSG,1> = 0 THEN ABORT ELSE RETURN
    SUBROUTINE SLIMPRIMANTE(SLFIL)
*==========================================================================
*= Programme : SLIMPRIMANTE
*= Version 1.1
*= Date de mise à jour : 96/04/25
*= Date de génération : 01/02/14
*===========================================================================
*= L'instruction suivante permet de connaître le numéro de version du       
*= programme compilé sous unix par la commande : what _[[NomProgramme]]         
*=                                                                          
[[NumeroDeVersionDuProgramme]] = "@(#)[SLIMPRIMANTE 1.1 96/04/25]"                      
*=                                                                          
*===========================================================================
*----------------------------------------------------------------------------
*-- PORTAGE
*-- UDT : Assignation des imprimantes dans un programme
*-- Creation : 17:02:10  16 Jan 1995  par ERG
*-- Version : 1.0
*-- Date de MAJ : 22 mai 1995
*-- MAJ :  ajout de la mise a jour du fichier [[SO_HOLD_]]
*-- Compile  : 
*----------------------------------------------------------------------------
*  SLFIL : liste des files a initialiser en MA hormis la 19
*----------------------------------------------------------------------------
    PROMPT ""
    LTAMPON = @DATA
    IFIN = DCOUNT(SLFIL,@AM)
* Recherche si entree verrouillee ou non
    THOLD = 0
    FOR I = 1 TO IFIN
      IF SLFIL<I> # 0 THEN THOLD = 1 ; GO 10
    NEXT I
10  NULL
*----------------------------------------------------------------------------
* Modif du 22 mai 1995
    SOHOLD = 1
    OPEN "DICT _HOLD_" TO FDHOLD  ELSE SOHOLD = 0
    OPEN "[[SO_HOLD_]]"    TO FSOHOLD ELSE SOHOLD = 0
**** Fin modif du 22 mai 1995
*----------------------------------------------------------------------------
* Selection de l'imprimante si pas verrouillee
    IF NOT(THOLD) THEN XDEST = ",DEST imp1" ELSE XDEST = ""
* Assignation des lignes
    CPT = 0
    FOR I = 1 TO IFIN
      XNOF = I - 1 ; MSF = SLFIL<I>
* Recherche si verrouillee ou non
      IF THOLD THEN XHOLD = 3 ELSE XHOLD = 1
* Recherche si BANNER UNIQUE avec message
      IF MSF # 0 THEN XBANNER = " ":MSF ELSE XBANNER = ""
* Preparation de la phrase
      PHRASE = 'SETPTR ':XNOF:',,,,,':XHOLD:',BANNER UNIQUE':XBANNER
      PHRASE = PHRASE:',NOHEAD':XDEST:',BRIEF'
* Envoi de l'initialisation
      EXECUTE PHRASE
**** Modif du 22 mai 1995
      IF SOHOLD = 1 AND XHOLD = 3 THEN
        READV NUM FROM FDHOLD,"NEXT.HOLD",1 ELSE NUM = 1
        NUM = NUM - 1
        IF XBANNER = "" THEN ITSOHOLD = "P_0000" ELSE ITSOHOLD = XBANNER[2,40]
        ITSOHOLD = ITSOHOLD:"_":NUM "R%4"
        WSOHOLD  = @DATE:@AM:@TIME:@AM:@LOGNAME:@AM:"N"
        READU EXIST FROM FSOHOLD,ITSOHOLD ELSE NULL
        WRITE WSOHOLD ON FSOHOLD,ITSOHOLD
      END
**** Fin modif du 22 mai 1995
    NEXT I
* Assignation de la file 19
    EXECUTE 'SETPTR 19,,,,,3,BANNER UNIQUE 19,NOHEAD,BRIEF'
**** Modif du 22 mai 1995
    IF SOHOLD = 1 THEN
      READV NUM FROM FDHOLD,"NEXT.HOLD",1 ELSE NUM = 1
      NUM = NUM - 1
      ITSOHOLD = "19_":NUM "R%4"
      WSOHOLD  = @DATE:@AM:@TIME:@AM:@LOGNAME:@AM:"N"
      READU EXIST FROM FSOHOLD,ITSOHOLD ELSE NULL
      WRITE WSOHOLD ON FSOHOLD,ITSOHOLD
    END
**** Fin modif du 22 mai 1995
* Remise en forme des tampons
    NBTAMPON = DCOUNT(LTAMPON,CHAR(13)) - 1
    FOR I = 1 TO NBTAMPON
      DATA FIELD(LTAMPON,CHAR(13),I)
    NEXT I
*
    RETURN