/* xlatex.c
 *
 * xlatex est une application X facilitant l'utilisation des produits de
 * composition de texte (tels que TeX et LaTeX) librement distribuable.
 * Mario Dragone en a un Copyright (1990). Vous pouvez modifier et
 * utiliser ce programme, a condition de lui envoyer les modifications. Il
 * peut etre inclus dans toute distribution, commerciale ou non, a
 * condition que cette notice et la banniere definie ci-dessous ne soient
 * pas modifies (sauf pour le numero de version) et que cette banniere
 * soit affichee a l'appel du programme. Toute contribution, correction
 * de bogue et commentaires doivent etre envoyes a :
 *
 * Mario Dragone,    IUT Vannes
 *		     rue Montaigne
 *		     BP 1104
 *		     56014 Vannes -  France
 *                   Tel: 99.46.31.06
 *
 * e-mail: dragone@iu-vannes.fr
 * 
 * picheral@univ-rennes1.fr 11/06/93 modifie pour HP-UX
 * picheral@univ-rennes1.fr 08/09/93 modifie pour IRIX
 *                                   message fin dvips
 * decouty@irisa.fr         23/09/93 modifie pour Solaris 2
 * picheral@univ-rennes1.fr 11/08/94 ressource et widget => pilote
 * picheral@univ-rennes1.fr 25/08/94 #define ALPR et ALPQ
 * picheral@univ-rennes1.fr 08/09/94 waitpid sur tous les fils en Solaris 2
 *				     sinon la terminaison de "xterm emacs"
 *				     terminait aussi xlatex !
 * picheral@univ-rennes1.fr 08/09/94 LG_NOM mis a 128 au lieu de 32
 *				     LG_PATH mis a MAXPATHLENGTH au lieu de 128
 */

#define VERSION "3.3c"
#define BANNER "xlatex, version %s -- Copyright(c) 1990-1994 CICB\n"

/************************************************************************
 * Application X concue autour des Athena Widgets pour faciliter
 * l'utilisation des commandes associees a TeX et LaTeX. Appel :
 *
 * xlatex [options] [document] [toolkit_options]
 *
 *
 * L'utilisateur dispose des boutons de commandes:
 *
 *      Faconner        faconnage du document courant
 *      Visionner       epreuvage sur ecran
 *	PostScript	production d'un document PostScript
 *      Imprimer        impression du document sur la station courante. Une
 *                      fenetre ``popup'' apparait pour positionner les options
 *                      telles que:
 *                              - commande d'impression et ses arguments
 *                              - station de sortie
 *                              - pages a imprimer
 *				- nb. de copies
 *      File d'attente  etat de l'imprimante
 *      Editer          session edition de texte
 *      Quitter         fin de l'application
 *
 * Les champs suivants sont egalement definis:
 *
 *      visionneur      utilitaire de visualisation sur ecran du document
 *      repertoire      repertoire courant de travail
 *      document        nom du document (correspond au nom du fichier sans
 *                      suffixe 'tex'
 *      faconnage       utilitaire de faconnage de documents
 *      editeur         editeur de texte
 *	pilote		pilote de conversion en PostScript
 *      interaction     c'est une fenetre 'ascenseur' qui recoit toutes les
 *                      sorties 'ecran' des commandes generees par selection
 *                      des boutons de commande. Elle permet egalement a
 *                      l'utilisateur d'introduire du texte pour notamment
 *                      dialoguer avec la commande latex.
 *
 * Voici la correspondance 'shell-like' des actions realisees par les boutons de
 * commande :
 *
 *      faconner        <faconnage> <document> &
 *      imprimer        <pilote> [-p page -n nbpages] [-c copies]
 *			       -o '!<impression>
 *                             -P<imprimante>' <document> & (BSD)
 *                             -d<imprimante>' <document> & (System V)
 *      visionner       <visionneur> <document> &
 *      file attente    lpq -P<imprimante> &    (BSD)
 *                      lpstat -o<imprimante> & (System V)
 *      editeur         xterm -e <editeur> <document>.tex &
 *
 * ***************************************************************************
 */

/*
 * Notes :
 * - xlatex est prevu pour utiliser les versions 5.4 et ulterieures de dvips
 */

/*
 * Versions :
 * 3.0   03/06/91: premiere version a diffusion restreinte X11R4
 * 3.1   26/06/91: version diffusable
 * 3.2   24/09/91: adaptation X11R5, meilleure designation des champs
 *		   et possibilite de deplacement par tabulation
 * 3.3   29/01/92: ajout du bouton PostScript et possibilite d'epreuver
 *		   le PostScript si le mode choisi est PostScript
 * 3.3a  03/12/92: ajout bouton xfig et amenagements mineurs
 * 3.3b  10/12/93: adaptations pour differentes plate-formes
 * 3.3c  11/08/94: ajout ressource et widget => pilote
 */

#include <stdio.h>
#include <errno.h>
#include <signal.h>
#include <search.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#include <sys/wait.h>
#include <sys/stat.h>
#include <sys/param.h>  /* pour MAXPATHLEN */

#include <X11/Xos.h>
#include <X11/Intrinsic.h>
#include <X11/StringDefs.h>
#include <X11/Shell.h>
#include <X11/Xaw/Command.h>
#include <X11/Xaw/Form.h>
#include <X11/Xaw/AsciiText.h>
#include <X11/Xaw/Label.h>
#include <X11/Xaw/Toggle.h>
#include <X11/Xaw/Dialog.h>
#include <X11/Xaw/SimpleMenu.h>
#include <X11/Xaw/SmeBSB.h>
#include <X11/Xaw/SmeLine.h>
#include <X11/Xaw/MenuButton.h>

#if (defined(SVR4) || defined(SYSV))
#include <sys/types.h>
#include <fcntl.h>
#if ! defined(HPUX) && ! defined(AIXV3) && ! defined(IRIX)
#include <sys/filio.h>  /* pour FIOREAD */
#endif
#endif

#include "icone.h"

#define LG_NOM    128
#define LG_FICH   MAXPATHLEN
#define LG_CHEMIN MAXPATHLEN
#define DVIPS   "dvips"
#if (defined(SVR4) || defined(SYSV)) && ! defined(BSD_COMP)
#define LPR   "lp"
#define ALPR   "-d"
#define ALPQ   "-o"
#define LPQ     "lpstat"
#else
#define LPR     "lpr"
#define ALPR   "-P"
#define ALPQ   "-P"
#define LPQ     "lpq"
#endif

#define POINT_INSERTION 999999


#if defined(SVR4)
char *sys_errlist[0230];
#else
char *sys_errlist[];
#endif
int errno;

extern char
#ifndef AIXV3
               *strrchr (),
#endif
#if (defined(SVR4) || defined(SYSV)) && ! defined(IRIX)
               *getcwd (), 
#else
               *getwd (),   
#endif
               *strtok (),
               *getenv ();
extern ENTRY   *hsearch ();


/* --- STATIQUES ---*/

/*
 * References en avant
 */

static          XtInputCallbackProc
                Procedure_entreeINP ();
static void     FaconnerCB (),
                VisionnerCB (),
                DessinerCB (),
                PostScriptCB (),
                ImprimerCB (),
                StatutCB (),
                EditerCB (),
                QuitterCB (),
		MenuVisionneursCB (),
		MenuVisionneursPSCB (),
                Toutes_pagesCB (),
                De_la_pageCB (),
                OkCB (),
                AnnulerCB ();
static          XtActionProc
		FocaliserACT (),
		ChampSuivantACT (),
                ControlACT (),
                InsertACT (),
                DeleteACT (),
                SendACT ();
static void     Connecter_pipes (),
                Reinitialiser_fenetre_interaction (),
                Supprimer_suffixe_tex ();

/*
 * Implementation des groupes de tabulation des champs de saisie
 * Chaque entree du tableau designe un widget et son suivant (chainage boucle)
 * Pour acceder a une entree par le nom d'un widget, on utilise la fonction
 * de hash-coding hsearch
 */
typedef struct {
    char	   *nom;
    int		    suivant;
    Widget	    wg;
}		_groupeT;

static _groupeT	TabGroup[15];
static int	IGroup = 0;
static ENTRY	TabElem;

/*
 * Tableau des widgets boutons de commande et leur fonction de CallBack
 */
typedef void    (*fptr) ();
typedef struct {
    char           *nom;
    fptr            CB;
    Widget          wg;
}               _commandesT;

static _commandesT Commandes[] = {
    {"editer", EditerCB},
    {"dessiner", DessinerCB},
    {"faconner", FaconnerCB},
    {"visionner", VisionnerCB},
    {"postscript", PostScriptCB},
    {"imprimer", ImprimerCB},
    {"statut", StatutCB},
    {"quitter", QuitterCB}
};


/*
 * Description des ressources de l'application Xlatex
 */

typedef struct _AppRessources {
    String          repertoire_initial,
		    dessin,
                    faconneur,
                    visionneurs,
                    visionneursPS,
		    pilote,
                    impression,
                    editeur;
    Boolean         editeur_avec_xterm;
    /* ressources maintenues pour compatibilite avec la version anterieure */
    String          repertoire;
}               RessourcesXlatex;

static RessourcesXlatex Ressources_xlatex;

static XtResource Ressources[] = {
    {"repertoireInitial", "RepertoireInitial", XtRString, sizeof (String),
	XtOffset (RessourcesXlatex *, repertoire_initial), XtRString, NULL},
    {"faconneur", "Faconneur", XtRString, sizeof (String),
	XtOffset (RessourcesXlatex *, faconneur), XtRString, "latex"},
    {"dessin", "Dessin", XtRString, sizeof (String),
	XtOffset (RessourcesXlatex *, dessin), XtRString, "xfig"},
    {"visionneurs", "Visionneurs", XtRString, sizeof (String),
	XtOffset (RessourcesXlatex *, visionneurs), XtRString, "*xdvi texx"},
    {"visionneursPS", "VisionneursPS", XtRString, sizeof (String),
	XtOffset (RessourcesXlatex *, visionneursPS), XtRString, "ghostview gs"},
    {"editeur", "Editeur", XtRString, sizeof (String),
	XtOffset (RessourcesXlatex *, editeur), XtRString, NULL},
    {"pilote", "Pilote", XtRString, sizeof (String),
	XtOffset (RessourcesXlatex *, pilote), XtRString, NULL},
    {"impression", "Impression", XtRString, sizeof (String),
	XtOffset (RessourcesXlatex *, impression), XtRString, LPR},
    {"editeurAvecXterm", "EditeurAvecXterm", XtRBoolean, sizeof (Boolean),
	XtOffset (RessourcesXlatex *, editeur_avec_xterm), XtRString, NULL},
};

static String   Ressources_defaut[] = {
    NULL,
};


/*
 * Table des actions
 */
static XtActionsRec Table_actions[] = {
    {"Focaliser", (XtActionProc) FocaliserACT},
    {"ChampSuivant", (XtActionProc) ChampSuivantACT},
    {"Control", (XtActionProc) ControlACT},
    {"Insert", (XtActionProc) InsertACT},
    {"Delete", (XtActionProc) DeleteACT},
    {"Send", (XtActionProc) SendACT},
    {"faconner", (XtActionProc) FaconnerCB},
    {"editer", (XtActionProc) EditerCB},
    {"dessiner", (XtActionProc) DessinerCB},
    {"visionner", (XtActionProc) VisionnerCB},
    {"postscript", (XtActionProc) PostScriptCB},
    {"imprimer", (XtActionProc) ImprimerCB},
    {"statut", (XtActionProc) StatutCB},
    {"quitter", (XtActionProc) QuitterCB},
    {NULL, NULL}
};

static Widget   Toplevel,
                Document_wg,
                Imprimer_wg,
                Form_wg,
                Popup_wg,
                Repertoire_wg,
                Visionneurs_wg,
                Faconneur_wg,
                Editeur_wg,
                Dessin_wg,
                Interaction_wg,
		Imprimante_wg,
		Impression_wg,
		Pilote_wg,
                ToutesLab_wg,
                DeLab_wg,
                De_wg,
                ALab_wg,
                A_wg,
		CopiesLab_wg,
		Copies_wg;
Widget		Focus = (Widget) NULL;

XtAppContext    Xlatex_app_con;
Display        *Dpy;

static int      Pipe_entree[2],
                Pipe_sortie[2];

static char     Faconneur[LG_NOM] = "",
                Editeur[LG_NOM] = "",
                Dessin[LG_NOM] = "",
                Impression[LG_NOM] = "",
                Visionneur[LG_NOM] = "",
                Document[LG_FICH] = "",
                Repertoire[LG_CHEMIN] = "",
		Pilote[LG_NOM] = "",
                Imprimante[LG_NOM] = "";
static Boolean	PostScript = False;

static int      FaconneurPid = -9999;
static Boolean	FaconneurActif = False;
static int      ImpressionPid = -9999;
static Boolean  ImpressionActive = False;
static int      PostScriptPid = -9999;
static Boolean  PostScriptActif = False;
static int	Pgid;
static char     TamponEntree[256] = "";
static int      TamponEntree_lg = 0;

static Boolean  ToutesPages = True,
                DeLaPage = False;

static char     PageDebut[5] = "0",
                PageFin[5] = "0",
                Pages[5] = "0",
		Copies[5] = "1";

static Pixel	CouleurDeBordure,
		CouleurDeFond;

static char    *TabArg[15];

static char    *Visionneurs[10],
	       *VisionneursPS[10];

static char     Programme[] = "Xlatex";


/* --- INTERNES --- */

#if (defined(SVR4) || defined(SYSV))
  killpg(ProcessGroup, Signal)
  int ProcessGroup;
  int Signal;
{   
if (ProcessGroup < 0)
  {
     errno = ESRCH;
      return (-1);
  }
  return (kill(-ProcessGroup, Signal));
  }
#endif

	/************************************************************
	  Changer_Repertoire

	  	- modification de la variable d'environnement PATH
	  	- changement de repertoire
	 ************************************************************/
	
static int      Changer_repertoire (repertoire)
/****************************************/
    char           *repertoire;
{
    extern char   **environ;
    static char   **nouvelEnviron = NULL;
    static char     pwdEnv[256];
    static Boolean  nouvelEnvCree = False;
    int             nbVarEnv;
    char          **newPtr,
                  **oldPtr;

    if (nouvelEnvCree == False) {

	/* Enumeration des variables d'environnement */
	for (oldPtr = environ; *oldPtr; oldPtr++);
	nbVarEnv = (oldPtr - environ);

	nouvelEnviron = (char **) XtMalloc ((nbVarEnv + 2) * sizeof (char **));
	if (!nouvelEnviron) {
	    fprintf (stderr,
	       "%s:  echec allocation de %d pointeurs de l'environnement\n",
		     Programme, nbVarEnv + 2);
	    exit (1);
	}
	/* placer PWD=repertoire en premiere position */
	strcpy (pwdEnv, "PWD=");
	newPtr = nouvelEnviron;
	*newPtr++ = pwdEnv;

	/* copie des autres variables de l'environnement */
	for (oldPtr = environ; *oldPtr; oldPtr++) {
	    if (strncmp (*oldPtr, "PWD=", 4) != 0)
		*newPtr++ = *oldPtr;
	}
	*newPtr = NULL;
	environ = nouvelEnviron;
	nouvelEnvCree = True;
    }
    /* Changement de repertoire */
    strcpy (pwdEnv + 4, repertoire);
    return (chdir (repertoire));
}


	/************************************************************
	 Connecter_pipes

	 On se situe dans le cadre d'un processus FILS.
	 Les organes d'E/S standard sont connectes aux pipes Pipe_entree
	 et Pipe_sortie :

	 0	recevra les caracteres en provenance du PERE
	 1,2	enverront les caracteres au PERE qui activera la procedure
	 	Procedure_entreeINP

				PERE		FILS
				[1] Pipe_entree [0] == 0
	 Procedure_entreeINP	[0] Pipe_sortie [1] == 1, 2

	 Ce processus est affilie au 'process group' de son pere ce qui
	 permet a ce dernier d'envoyer un signal de terminaison a
         l'ensemble du groupe en fin d'application
	 ************************************************************/
	
static void     Connecter_pipes ()
/****************************************/
{
    long            arg;
    char            buf[32];
    int             len;

    /*
       On se situe ici dans le cadre d'un processus qui s'est cree mais avant
       qu'il ne realise l'execvp. on connecte 0, 1 et 2 aux pipes d'E/S
    */
    dup2 (Pipe_entree[0], 0);
    dup2 (Pipe_sortie[1], 1);
    dup2 (Pipe_sortie[1], 2);

    close (Pipe_entree[0]);
    close (Pipe_entree[1]);
    close (Pipe_sortie[0]);
    close (Pipe_sortie[1]);

    /* Purge des entrees anticipees */
    ioctl (0, FIONREAD, &arg);
#ifndef IRIX
    while (arg > 0) {
	len = read (0, buf, sizeof (buf));
	ioctl (0, FIONREAD, &arg);
    }
#endif
}


	/************************************************************
	 Afficher

	 Affichage d'un message suivi d'un retour a la ligne
	 dans le widget Interaction.
	 ************************************************************/
	
static int      Afficher (msg)
/****************************************/
    char           *msg;
{
    char            aLaLigne = '\n';
    XawTextBlock    text;

    /* On affiche le message dans la fenetre d'interaction */
    text.firstPos = 0;
    text.ptr = msg;
    text.format = FMT8BIT;
    text.length = strlen (msg);

    XawTextReplace (Interaction_wg, POINT_INSERTION, POINT_INSERTION, &text);

    text.ptr = &aLaLigne;
    text.length = 1;

    XawTextReplace (Interaction_wg, POINT_INSERTION, POINT_INSERTION, &text);
    XawTextSetInsertionPoint (Interaction_wg, POINT_INSERTION);

    XFlush (Dpy);
}


	/************************************************************
	 Reinitialiser_fenetre_interaction

	 Effacement du contenu du widget Interaction, generalement
	 provoque a chaque faconnage
	 ************************************************************/
	
static void     Reinitialiser_fenetre_interaction ()
/****************************************/
{
    XawTextBlock    text;
    char            car = '\00';

    text.firstPos = 0;
    text.ptr = &car;
    text.format = FMT8BIT;
    text.length = 0;

    XawTextReplace (Interaction_wg, (XawTextPosition) 0, POINT_INSERTION, &text);
    XawTextSetInsertionPoint (Interaction_wg, POINT_INSERTION);
}


	/************************************************************
	 Supprimer_suffixe_tex

	 Suppression du suffixe .tex du champ Document. Un suffixe
	 approprie est ajoute ulterieurement.
	 ************************************************************/
	
static void     Supprimer_suffixe_tex ()
/****************************************/
{
    char           *ptex;
    if ((ptex = rindex (Document, '.')) == NULL)
	return;
    if (strcmp (ptex, ".tex") == 0) {
	*ptex = '\00';
	XtVaSetValues (Document_wg, XtNstring, Document, NULL);
    }
}


	/************************************************************
	 Positionner_arguments

	 Analyse une ligne de commande et positionne le tableau
	 d'arguments TabArg
	 ************************************************************/
	
static void     Positionner_arguments (commande)
/****************************************/
    char	   *commande;
{
    int		    i = 0;
    TabArg[i] = strtok (commande, " ");
    while ((TabArg[++i] = strtok (NULL, " ")) != NULL);
}


	/************************************************************
	 Acquitter_processus

	 Reaction au signal de terminaison SIGCHLD.
	 Dans le cas du processus de faconnage, d'impression et de
	 generation PoscScript, on memorise et signale
	 sa terminaison.
	 ************************************************************/
	
static void     Acquitter_processus ()
/****************************************/
{
    int		    status;
    int             pid;

#if defined(SVR4)
    while ((pid = waitpid ((pid_t) -1, &status, WNOHANG)) > 0) {
#else
#if defined(SYSV) && ! defined(IRIX)
    while ((pid = waitpid ((pid_t) 0, &status, WNOHANG)) > 0) {
#else
    while ((pid = wait3 (&status, WNOHANG, 0)) > 0) {
#endif
#endif
        if (pid == FaconneurPid) {
            char            msg[256];
            FaconneurActif = False;
            sprintf (msg, "--- Exit %s ---", Faconneur);
            Afficher (msg);
        }
        if (pid == ImpressionPid) {
            char            msg[256];
            ImpressionActive = False;
            sprintf (msg, "--- Exit %s ---", Impression);
            Afficher (msg);
        }
        if (pid == PostScriptPid) {
            char            msg[256];
            PostScriptActif = False;
            sprintf (msg, "--- Exit %s ---", Pilote);
            Afficher (msg);
        }
    }
    signal (SIGCHLD, Acquitter_processus);
}


	/************************************************************
	 Initialiser_pipes

	 Creation des pipes Pipe_entree et Pipe_sortie
	 ************************************************************/
	
static void     Initialiser_pipes ()
/****************************************/
{
    pipe (Pipe_entree);
    pipe (Pipe_sortie);
#if (defined(SVR4) || defined(SYSV))
    fcntl (Pipe_entree[1], F_SETFL, O_NDELAY);
    fcntl (Pipe_sortie[0], F_SETFL, O_NDELAY);
#else
    fcntl (Pipe_entree[1], F_SETFL, FNDELAY);
    fcntl (Pipe_sortie[0], F_SETFL, FNDELAY);
#endif
}


	/************************************************************
	 Initialiser_Xt

	 Creation de l'application Xlatex, traitement des ressources
	 et initialisation de l'environnement de travail
	 ************************************************************/
	
static void     Initialiser_Xt (argc, argv)
/****************************************/
    int             argc;
    char           *argv[];
{
    char            msg[256];
    char            titre[256];
    char           *rep,
                   *doc,
                   *imp,
                   *edi;
    int		    iv;
    char	   *vp;

    /* Initialisation du processus de hash-coding : on prevoit 15 entrees max */
    hcreate (15);

    /*
       Interception du signal de changement d'etat (en l'occurence leur
       terminaison) des processus fils pour eviter leur etat <defunct>
    */
    signal (SIGCHLD, Acquitter_processus);


    /* Demarrage de l'application X */
    Toplevel = XtAppInitialize (&Xlatex_app_con, Programme, NULL,
			0, &argc, argv,
			Ressources_defaut, NULL, 0);

    Dpy = XtDisplay (Toplevel);

    XtAppAddActions (Xlatex_app_con, Table_actions, XtNumber (Table_actions));
    XtAppAddInput (Xlatex_app_con, Pipe_sortie[0], (XtPointer) XtInputReadMask,
			(XtInputCallbackProc) Procedure_entreeINP, NULL);

    /* Obtention des ressources de l'application */
    XtGetApplicationResources (Toplevel, (XtPointer) & Ressources_xlatex,
			Ressources, XtNumber (Ressources), NULL, 0);

    /* Fabrication des listes des visionneurs */
    Visionneur[0] = '\0';
    iv = 0;
    vp = strtok (Ressources_xlatex.visionneurs, " ,");
    while (vp) {
    	if (*vp == '*') {
    	   vp++;
    	   strcpy (Visionneur, vp);
	   PostScript = False;
    	}
    	Visionneurs[iv++]=vp;
	vp = strtok (NULL, " ,");
    }
    iv = 0;
    vp = strtok (Ressources_xlatex.visionneursPS, " ,");
    while (vp) {
    	if (*vp == '*') {
    	   vp++;
    	   strcpy (Visionneur, vp);
	   PostScript = True;
    	}
    	VisionneursPS[iv++]=vp;
	vp = strtok (NULL, " ,");
    }

    if (! Visionneur[0]) {
    	strcpy (Visionneur, Visionneurs[0]);
	PostScript = False;
    }
    
    /* Prise en compte des anciens noms de ressources */
    if (Ressources_xlatex.repertoire != NULL)
	Ressources_xlatex.repertoire_initial = Ressources_xlatex.repertoire;

    /* Fabrication de l'icone */
    xlatex_bitmap = XCreateBitmapFromData (Dpy,
			RootWindow (Dpy, DefaultScreen (Dpy)),
			xlatex_bits, xlatex_width, xlatex_height);
    sprintf (titre, "%s %s", Programme, VERSION);
    XtVaSetValues (Toplevel,
			XtNiconPixmap, xlatex_bitmap,
			XtNtitle, titre,
			NULL);

    /*
       Determination du nom du document. S'il est fourni en parametre : son
       chemin d'acces est expanse et on en deduit le repertoire et son nom
       sinon si la ressource repertoireInitial est positionnee : elle devient
       le repertoire courant de travail sinon le repertoire courant est pris
    */

    if (argc > 1) {
	doc = strrchr (argv[1], '/');
	if (doc == NULL)
	    strcpy (Document, argv[1]);
	else {
	    strcpy (Document, doc + 1);
	    *doc = '\00';
	    if (Changer_repertoire (argv[1]) == -1) {
		sprintf (msg, "chdir %s", argv[1]);
		perror (msg);
		exit (1);
	    }
	}
    } else {
	strcpy (Document, "document");
	if (Ressources_xlatex.repertoire_initial != NULL) {
	    if (Changer_repertoire (Ressources_xlatex.repertoire_initial) == -1) {
		sprintf (msg, "chdir %s", Ressources_xlatex.repertoire_initial);
		perror (msg);
		exit (1);
	    }
	}
    };
#if (defined(SVR4) ||defined(SYSV)) && ! defined(IRIX)
    rep = getcwd (Repertoire, MAXPATHLEN);
#else
    rep = getwd (Repertoire);
#endif

    /*
       Obtention du nom de l'imprimante et de l'editeur par les variables
       d'environnement.
    */
#if (defined(SVR4) || defined(SYSV)) && ! defined(BSD_COMP)
    imp = getenv ("LPDEST");
#else
    imp = getenv ("PRINTER");
#endif
    if (imp != NULL)
	strcpy (Imprimante, imp);
    if (Ressources_xlatex.editeur == NULL) {
	edi = getenv ("EDITOR");
	if (edi != NULL)
	    strcpy (Editeur, edi);
	else
	    strcpy (Editeur, "emacs");
    } else
	strcpy (Editeur, Ressources_xlatex.editeur);
    if (Ressources_xlatex.pilote != NULL)
    	strcpy (Pilote, Ressources_xlatex.pilote);
    else
    	strcpy (Pilote, DVIPS);
    strcpy (Dessin, Ressources_xlatex.dessin);
    strcpy (Faconneur, Ressources_xlatex.faconneur);
    strcpy (Impression, Ressources_xlatex.impression);
}



	/************************************************************
	 Creer_popup_imprimer

	 Creation du formulaire d'impression
	 Creation du groupe secondaire de tabulation pour ce formulaire.
	 IGroup designe la derniere entree occupee dans TabGroup
	 ************************************************************/
	
static void     Creer_popup_imprimer ()
/****************************************/
{
    Widget          form_wg,
                    impressionLab_wg,
                    imprimanteLab_wg,
                    toutesTog_wg,
                    deTog_wg,
                    ok_wg,
                    annuler_wg;
    Widget          widgets[30];
    Cardinal        nwg = 0;
    int		    debut;
    
    Popup_wg = XtVaCreatePopupShell ("popup", transientShellWidgetClass, Form_wg, NULL);
    form_wg = XtVaCreateManagedWidget ("form", formWidgetClass, Popup_wg, NULL);

    widgets[nwg++] = impressionLab_wg = XtVaCreateWidget ("impressionLab", labelWidgetClass, form_wg,
				NULL);

    debut = ++IGroup;
    TabGroup[IGroup].suivant = IGroup + 1;
    TabGroup[IGroup].nom = "impression";
    TabGroup[IGroup].wg = widgets[nwg++] = Impression_wg = XtVaCreateWidget (TabGroup[IGroup].nom, asciiTextWidgetClass, form_wg,
				XtNstring, Impression,
				XtNlength, LG_NOM,
				XtNborderColor, CouleurDeFond,
				NULL);

    widgets[nwg++] = imprimanteLab_wg = XtVaCreateWidget ("imprimanteLab", labelWidgetClass, form_wg,
				NULL);

    IGroup++;
    TabGroup[IGroup].suivant = IGroup + 1;
    TabGroup[IGroup].nom = "imprimante";
    TabGroup[IGroup].wg = widgets[nwg++] = Imprimante_wg = XtVaCreateWidget (TabGroup[IGroup].nom, asciiTextWidgetClass, form_wg,
				XtNstring, Imprimante,
				XtNlength, LG_NOM,
				XtNborderColor, CouleurDeFond,
				NULL);

    widgets[nwg++] = toutesTog_wg = XtVaCreateWidget ("toutesTog", toggleWidgetClass, form_wg,
				XtNstate, ToutesPages,
				NULL);
    XtAddCallback (toutesTog_wg, XtNcallback, Toutes_pagesCB, NULL);

    widgets[nwg++] = ToutesLab_wg = XtVaCreateWidget ("toutesLab", labelWidgetClass, form_wg,
				XtNsensitive, ToutesPages,
				NULL);

    widgets[nwg++] = deTog_wg = XtVaCreateWidget ("deTog", toggleWidgetClass, form_wg,
				XtNradioGroup, toutesTog_wg,
				XtNstate, DeLaPage,
				NULL);
    XtAddCallback (deTog_wg, XtNcallback, De_la_pageCB, NULL);

    widgets[nwg++] = DeLab_wg = XtVaCreateWidget ("deLab", labelWidgetClass, form_wg,
				XtNsensitive, DeLaPage,
				NULL);

    IGroup++;
    TabGroup[IGroup].suivant = IGroup + 1;
    TabGroup[IGroup].nom = "de";
    TabGroup[IGroup].wg = widgets[nwg++] = De_wg = XtVaCreateWidget (TabGroup[IGroup].nom, asciiTextWidgetClass, form_wg,
				XtNstring, PageDebut,
				XtNlength, sizeof (PageDebut),
				XtNwidth, 35,
				XtNsensitive, DeLaPage,
				XtNborderColor, CouleurDeFond,
				NULL);


    widgets[nwg++] = ALab_wg = XtVaCreateWidget ("aLab", labelWidgetClass, form_wg,
				XtNsensitive, DeLaPage,
				NULL);

    IGroup++;
    TabGroup[IGroup].suivant = IGroup + 1;
    TabGroup[IGroup].nom = "a";
    TabGroup[IGroup].wg = widgets[nwg++] = A_wg = XtVaCreateWidget (TabGroup[IGroup].nom, asciiTextWidgetClass, form_wg,
				XtNstring, PageFin,
				XtNlength, sizeof (PageFin),
				XtNwidth, 35,
				XtNsensitive, DeLaPage,
				XtNborderColor, CouleurDeFond,
				NULL);

    widgets[nwg++] = ok_wg = XtVaCreateWidget ("ok", commandWidgetClass, form_wg,
				NULL);

    XtAddCallback (ok_wg, XtNcallback, OkCB, NULL);

    widgets[nwg++] = annuler_wg = XtVaCreateWidget ("annuler", commandWidgetClass, form_wg,
				NULL);
    XtAddCallback (annuler_wg, XtNcallback, AnnulerCB, NULL);

    widgets[nwg++] = CopiesLab_wg = XtVaCreateWidget ("copiesLab", labelWidgetClass, form_wg,
				NULL);

    IGroup++;
    TabGroup[IGroup].suivant = debut;
    TabGroup[IGroup].nom = "copies";
    TabGroup[IGroup].wg = widgets[nwg++] = Copies_wg = XtVaCreateWidget (TabGroup[IGroup].nom, asciiTextWidgetClass, form_wg,
				XtNstring, Copies,
				XtNlength, sizeof (Copies),
				XtNwidth, 35,
				XtNborderColor, CouleurDeFond,
				NULL);
                                                                                                                               
    XtManageChildren (widgets, nwg);


    /* Hash-coding du groupe de tabulation cree */

    {
    	int	i;
    	for (i=debut; i<= IGroup; i++) {
    		TabElem.key = TabGroup[i].nom;
		TabElem.data= (char *) &TabGroup[i].suivant;
		hsearch (TabElem, ENTER);
	}
    }

}


	/************************************************************
	 Creer_widgets

	 Creation des widgets de l'application Xlatex
	 Creation du groupe principal de tabulation dans TabGroup
	 ************************************************************/
	
static void     Creer_widgets ()
/****************************************/
{
    Widget          repertoireLab_wg,
    		    modeLab_wg,
                    documentLab_wg,
                    dessinLab_wg,
                    visionneursLab_wg,
		    menuVisionneurs_wg,
                    faconneurLab_wg,
		    piloteLab_wg,
                    editeurLab_wg;		    
    Widget          widgets[32];
    WidgetList	    bouttons;
    Widget	    wg;
    int		    iv, i;
    Cardinal        nwg = 0;

    Form_wg = XtVaCreateManagedWidget ("form", formWidgetClass, Toplevel, NULL);

    for (i = 0; i < XtNumber (Commandes); i++) {
	widgets[nwg++] = Commandes[i].wg = XtVaCreateWidget (
				Commandes[i].nom, commandWidgetClass, Form_wg,
				XtNfromHoriz, (i == 0 ? NULL : Commandes[i - 1].wg),
				NULL);
	XtAddCallback (Commandes[i].wg, XtNcallback, Commandes[i].CB, NULL);
    }
    widgets[nwg++] = repertoireLab_wg = XtVaCreateWidget ("repertoireLab", labelWidgetClass, Form_wg,
				NULL);
    IGroup = 0;
    TabGroup[IGroup].suivant = IGroup + 1;
    TabGroup[IGroup].nom = "repertoire";
    TabGroup[IGroup].wg = widgets[nwg++] = Repertoire_wg = XtVaCreateWidget (TabGroup[IGroup].nom, asciiTextWidgetClass, Form_wg,
				XtNstring, Repertoire,
				XtNlength, LG_CHEMIN,
				NULL);

    XtVaGetValues (Repertoire_wg,
    				XtNbackground, &CouleurDeFond,
    				XtNborderColor, &CouleurDeBordure,
    				NULL);
    XtVaSetValues (Repertoire_wg,
				XtNborderColor, CouleurDeFond,
				NULL);
				
    widgets[nwg++] = dessinLab_wg = XtVaCreateWidget ("dessinLab", labelWidgetClass, Form_wg,
				NULL);

    IGroup++;
    TabGroup[IGroup].suivant = IGroup + 1;
    TabGroup[IGroup].nom = "dessin";
    TabGroup[IGroup].wg = widgets[nwg++] = Dessin_wg = XtVaCreateWidget (TabGroup[IGroup].nom, asciiTextWidgetClass, Form_wg,
				XtNstring, Dessin,
				XtNlength, LG_NOM,
				XtNborderColor, CouleurDeFond,
				NULL);

    widgets[nwg++] = documentLab_wg = XtVaCreateWidget ("documentLab", labelWidgetClass, Form_wg,
				NULL);

    IGroup++;
    TabGroup[IGroup].suivant = IGroup + 1;
    TabGroup[IGroup].nom = "document";
    TabGroup[IGroup].wg = widgets[nwg++] = Document_wg = XtVaCreateWidget (TabGroup[IGroup].nom, asciiTextWidgetClass, Form_wg,
				XtNstring, Document,
				XtNlength, LG_NOM,
				XtNborderColor, CouleurDeFond,
				NULL);

    widgets[nwg++] = visionneursLab_wg = XtVaCreateWidget ("visionneursLab", labelWidgetClass, Form_wg,
				NULL);

    widgets[nwg++] = Visionneurs_wg = XtVaCreateManagedWidget ("visionneurs", menuButtonWidgetClass, Form_wg,
    				XtNmenuName, "menuVisionneurs",
				XtNlabel, Visionneur,
    				NULL);
    				
    menuVisionneurs_wg = XtVaCreatePopupShell ("menuVisionneurs", simpleMenuWidgetClass, Visionneurs_wg, NULL);
    
    iv = 0;
    while (Visionneurs[iv]) {
    	wg = XtVaCreateManagedWidget (Visionneurs[iv], smeBSBObjectClass, menuVisionneurs_wg,
				NULL);
    	XtAddCallback (wg, XtNcallback, MenuVisionneursCB, (XtPointer) iv);
    	iv++;
    }
    XtVaCreateManagedWidget ("separateur", smeLineObjectClass, menuVisionneurs_wg, NULL);
    iv = 0;
    while (VisionneursPS[iv]) {
    	wg = XtVaCreateManagedWidget (VisionneursPS[iv], smeBSBObjectClass, menuVisionneurs_wg,
				NULL);
    	XtAddCallback (wg, XtNcallback, MenuVisionneursPSCB, (XtPointer) iv);
    	iv++;
    }
    

    widgets[nwg++] = faconneurLab_wg = XtVaCreateWidget ("faconneurLab", labelWidgetClass, Form_wg,
				NULL);

    IGroup++;
    TabGroup[IGroup].suivant = IGroup + 1;
    TabGroup[IGroup].nom = "faconneur";
    TabGroup[IGroup].wg = widgets[nwg++] = Faconneur_wg = XtVaCreateWidget (TabGroup[IGroup].nom, asciiTextWidgetClass, Form_wg,
				XtNstring, Faconneur,
				XtNlength, LG_NOM,
				XtNborderColor, CouleurDeFond,
				NULL);

    widgets[nwg++] = editeurLab_wg = XtVaCreateWidget ("editeurLab", labelWidgetClass, Form_wg,
				NULL);

    IGroup++;
    TabGroup[IGroup].suivant = IGroup + 1;
    TabGroup[IGroup].nom = "editeur";
    TabGroup[IGroup].wg = widgets[nwg++] = Editeur_wg = XtVaCreateWidget (TabGroup[IGroup].nom, asciiTextWidgetClass, Form_wg,
				XtNstring, Editeur,
				XtNlength, LG_NOM,
				XtNborderColor, CouleurDeFond,
				NULL);

    widgets[nwg++] = piloteLab_wg = XtVaCreateWidget ("piloteLab", labelWidgetClass, Form_wg,
				NULL);

    IGroup++;
    TabGroup[IGroup].suivant = 0;
    TabGroup[IGroup].nom = "pilote";
    TabGroup[IGroup].wg = widgets[nwg++] = Pilote_wg = XtVaCreateWidget (TabGroup[IGroup].nom, asciiTextWidgetClass, Form_wg,
				XtNstring, Pilote,
				XtNlength, LG_NOM,
				XtNborderColor, CouleurDeFond,
				NULL);

    widgets[nwg++] = Interaction_wg = XtVaCreateWidget ("interaction", asciiTextWidgetClass, Form_wg,
				XtNtop, XtChainTop,
				XtNright, XtChainRight,
				XtNleft, XtChainLeft,
				XtNbottom, XtChainBottom,
				XtNuseStringInPlace, False,
				NULL);

    XtManageChildren (widgets, nwg);

    /* Ajustement de la taille de la fenetre d'interaction */

    {
	Dimension       largeur;
	XFontStruct    *police;
	XtVaGetValues (Interaction_wg, XtNfont, &police, NULL);
	largeur = (police->max_bounds.width + police->min_bounds.width) / 2;
	XtVaSetValues (Interaction_wg, XtNwidth, largeur * 80 + 05,
				XtNheight, (police->max_bounds.ascent + police->max_bounds.descent) * 20 + 10,
                                NULL);
    }
                                                  
    Supprimer_suffixe_tex ();

    /* Hash-coding du groupe de tabulation */

    {
    	int	i;
    	for (i=0; i<= IGroup; i++) {
    		TabElem.key = TabGroup[i].nom;
		TabElem.data= (char *) &TabGroup[i].suivant;
		hsearch (TabElem, ENTER);
	}
    }

    Focus = Repertoire_wg;
}


	/************************************************************
	 Installer_accelerateurs

	 Mise en place des accelerateurs
	 ************************************************************/

static void	Installer_accelerateurs ()
/****************************************/
{
    XtInstallAllAccelerators (Toplevel, Toplevel);
    XtInstallAllAccelerators (Repertoire_wg, Toplevel);
    XtInstallAllAccelerators (Document_wg, Toplevel);
    XtInstallAllAccelerators (Visionneurs_wg, Toplevel);
    XtInstallAllAccelerators (Dessin_wg, Toplevel);
    XtInstallAllAccelerators (Faconneur_wg, Toplevel);
    XtInstallAllAccelerators (Pilote_wg, Toplevel);
    XtInstallAllAccelerators (Editeur_wg, Toplevel);
    XtInstallAllAccelerators (Interaction_wg, Toplevel);
    XtInstallAllAccelerators (Imprimante_wg, Toplevel);
    XtInstallAllAccelerators (Impression_wg, Toplevel);
}


/* --- INPUT READ PROCEDURE --- */

	/************************************************************
	 Procedure_entreeINP

	 Procedure activee lors de la presence de caracteres dans le
	 pipe Pipe_sortie[0]. 
	 ************************************************************/
	
static XtInputCallbackProc Procedure_entreeINP (cd, s, id)
/****************************************/
    caddr_t         cd;
    int            *s;
    XtInputId      *id;
{
    char            tamp[100];
    XawTextBlock    text;

    text.firstPos = 0;
    text.ptr = tamp;
    text.format = FMT8BIT;

    /* Boucle de transfert */
    while ((text.length = read (*s, tamp, sizeof (tamp))) > 0)
	XawTextReplace (Interaction_wg, POINT_INSERTION, POINT_INSERTION, &text);

    XawTextSetInsertionPoint (Interaction_wg, POINT_INSERTION);

    return (0);
}


/* --- CALLBACKS --- */

	/************************************************************
	 OkCB

	 Confirmation de l'impression. La commande d'impression est
	 preparee puis executee.
	 ************************************************************/
	
static void     OkCB (w, client_data, call_data)
/****************************************/
    Widget          w;
    XtPointer       client_data,
                    call_data;
{
    int             pd;
    int             pf;
    int             cp;
    int		    etat;
    char            msg[256];

    /* Calcul du nombre de pages a sortir dans Pages */
    pd = atoi (PageDebut);
    pf = atoi (PageFin);

    sprintf (Pages, "%d", (pf - pd) + 1);

    if (DeLaPage == True)
	if (pd > pf) {
	    Afficher ("Mauvais parametres de pages. DEB > FIN !");
	    return;
	}
    cp = atoi (Copies);
    if (cp < 1) {
	Afficher ("Nombre de copies errone !");
	return;
    }
    if (Changer_repertoire (Repertoire) == -1) {
	sprintf (msg, "%s: %s", Repertoire, sys_errlist[errno]);
	Afficher (msg);
	return;
    }
    Reinitialiser_fenetre_interaction ();
    Supprimer_suffixe_tex ();
    if (DeLaPage == True)
	if (cp > 1)
	    sprintf (msg, "%s -c %s -p %s -n %s -o '!%s %s%s' %s", Pilote,
	                  Copies, PageDebut, Pages, Impression, ALPR,
			  Imprimante, Document);
	else
            sprintf (msg, "%s -p %s -n %s -o '!%s %s%s' %s", Pilote, PageDebut,
                     Pages, Impression, ALPR, Imprimante, Document);
    else
	if (cp > 1)
            sprintf (msg, "%s -c %s -o '!%s %s%s' %s", Pilote, Copies,
                     Impression, ALPR, Imprimante, Document);
	else
            sprintf (msg, "%s -o '!%s %s%s' %s", Pilote, Impression,
                     ALPR, Imprimante, Document);
    Afficher (msg);
    ImpressionActive = True;
    if ((ImpressionPid = fork ()) == 0) {
        sprintf (msg, "!%s %s%s", Impression, ALPR, Imprimante);
	Connecter_pipes ();
	if (DeLaPage == True)
	    if (cp > 1)
		etat = execlp (Pilote, Pilote, "-c", Copies, "-p", PageDebut,
			       "-n", Pages, "-o", msg, Document, '\00');
	    else
	        etat = execlp (Pilote, Pilote, "-p", PageDebut,
			       "-n", Pages, "-o", msg, Document, '\00');
	else
	    if (cp > 1)
		etat = execlp (Pilote, Pilote, "-c", Copies, "-o", msg, Document,
                           '\00');
            else
	        etat = execlp (Pilote, Pilote, "-o", msg, Document, '\00');
	if (etat == -1) {
	    printf ("%s est inaccessible.\n", Pilote);
	    exit (-1);
	}
    }
    else if (ImpressionPid == -1) {
    	sprintf (msg, "fork: %s", sys_errlist[errno]);
    	Afficher (msg);
        ImpressionActive = False;
    }
    XtPopdown (Popup_wg);
}


	/************************************************************
	 MenuVisionneursCB

	 Selection d'un visionneur 
	 ************************************************************/
	
static void     MenuVisionneursCB (w, client_data, call_data)
/****************************************/
    Widget          w;
    XtPointer       client_data,
                    call_data;
{
    int 	    iv = (int) client_data;
    strcpy (Visionneur, Visionneurs[iv]);
    PostScript = False;
    XtVaSetValues (Visionneurs_wg, XtNlabel, Visionneur, NULL);
}


	/************************************************************
	 MenuVisionneursPSCB

	 Selection d'un visionneur PostScript
	 ************************************************************/
	
static void     MenuVisionneursPSCB (w, client_data, call_data)
/****************************************/
    Widget          w;
    XtPointer       client_data,
                    call_data;
{
    int 	    iv = (int) client_data;
    strcpy (Visionneur, VisionneursPS[iv]);
    PostScript = True;
    XtVaSetValues (Visionneurs_wg, XtNlabel, Visionneur, NULL);
}


	/************************************************************
	 AnnulerCB

	 Abandon de l'impression
	 ************************************************************/
	
static void     AnnulerCB (w, client_data, call_data)
/****************************************/
    Widget          w;
    XtPointer       client_data,
                    call_data;
{
    XtPopdown (Popup_wg);
}


	/************************************************************
	 De_la_pageCB

	 Selection de l'option 'de la page nn a mm', desensibilisation
	 de l'option 'toutes les pages'
	 ************************************************************/
	
static void     De_la_pageCB (w, client_data, call_data)
/****************************************/
    Widget          w;
    XtPointer       client_data,
                    call_data;
{
    Boolean         etat;

    XtVaGetValues (w, XtNstate, &etat, NULL);
    if (etat == True) {
	DeLaPage = True;
	XtVaSetValues (DeLab_wg, XtNsensitive, True, NULL);
	XtVaSetValues (De_wg, XtNsensitive, True, NULL);
	XtVaSetValues (ALab_wg, XtNsensitive, True, NULL);
	XtVaSetValues (A_wg, XtNsensitive, True, NULL);
    } else {
	DeLaPage = False;
	XtVaSetValues (DeLab_wg, XtNsensitive, False, NULL);
	XtVaSetValues (De_wg, XtNsensitive, False, NULL);
	XtVaSetValues (ALab_wg, XtNsensitive, False, NULL);
	XtVaSetValues (A_wg, XtNsensitive, False, NULL);
    }
}


	/************************************************************
	 Toutes_pagesCB

	 Selection de l'option 'toutes les pages' et desensibilisation
	 de l'option 'de la page nn a mm'
	 ************************************************************/
	
static void     Toutes_pagesCB (w, client_data, call_data)
/****************************************/
    Widget          w;
    XtPointer       client_data,
                    call_data;
{
    Boolean         etat;

    XtVaGetValues (w, XtNstate, &etat, NULL);
    if (etat == True) {
	ToutesPages = True;
	XtVaSetValues (ToutesLab_wg, XtNsensitive, True, NULL);
    } else {
	ToutesPages = False;
	XtVaSetValues (ToutesLab_wg, XtNsensitive, False, NULL);
    }
}


	/************************************************************
	 ImprimerCB

	 Apparition du formulaire d'impression
	 ************************************************************/
	
static void     ImprimerCB (w, client_data, call_data)
/****************************************/
    Widget          w;
    XtPointer       client_data,
                    call_data;
{
    Position        x,
                    y;
    Dimension       largeur,
                    hauteur;

    /* Calcul des coordonnees en fonction de celles de l'application */
    XtVaGetValues (Toplevel,
		   XtNwidth, &largeur,
		   XtNheight, &hauteur,
		   NULL);
    XtTranslateCoords (Form_wg, (Position) (largeur / 3), (Position) (hauteur / 3), &x, &y);

    XtVaSetValues (Popup_wg,
		   XtNx, x,
		   XtNy, y,
		   NULL);

    XtPopup (Popup_wg, XtGrabNone);
    XRaiseWindow (Dpy, XtWindow (Popup_wg));
}


	/************************************************************
	 VisionnerCB

	 Execution de la commande de visionnage
	 ************************************************************/
	
static void     VisionnerCB (w, client_data, call_data)
/****************************************/
    Widget          w;
    XtPointer       client_data,
                    call_data;
{
    char            msg[255];
    int		    pid;

    if (Changer_repertoire (Repertoire) == -1) {
	sprintf (msg, "%s: %s", Repertoire, sys_errlist[errno]);
	Afficher (msg);
	return;
    }
    Supprimer_suffixe_tex ();
    if (PostScript == True) {
    	struct stat dvi,
    		    ps;
        char	    fdvi[LG_CHEMIN],
        	    fps[LG_CHEMIN];
        sprintf (fdvi, "%s.dvi", Document);
        sprintf (fps , "%s.ps" , Document);
        if (stat (fdvi, &dvi) == 0) {
            if (stat (fps, &ps) == 0) {
            	if (dvi.st_mtime > ps.st_mtime) {
            	    sprintf (msg, "PSST !!  %s.ps n'est pas a jour ...");
            	    Afficher (msg);
            	}
            }
        }
	sprintf (msg, "%s %s.ps", Visionneur, Document);
    }
    else
	sprintf (msg, "%s %s.dvi", Visionneur, Document);
    Afficher (msg);
    Positionner_arguments (msg);
    if ((pid = fork ()) == 0) {
	Connecter_pipes ();
	if (execvp (TabArg[0], TabArg) == -1) {
	    printf ("%s n'a pas marche.\n", msg);
	    exit (-1);
	}

    }
    else if (pid == -1) {
    	sprintf (msg, "fork: %s", sys_errlist[errno]);
    	Afficher (msg);
    }
}


	/************************************************************
	 DessinerCB

	 Execution de la commande de dessin
	 ************************************************************/
	
static void     DessinerCB (w, client_data, call_data)
/****************************************/
    Widget          w;
    XtPointer       client_data,
                    call_data;
{
    char            msg[255];
    int		    pid;

    if (Changer_repertoire (Repertoire) == -1) {
	sprintf (msg, "%s: %s", Repertoire, sys_errlist[errno]);
	Afficher (msg);
	return;
    }
    sprintf (msg, "%s", Dessin);
    Afficher (msg);
    Positionner_arguments (msg);
    if ((pid = fork ()) == 0) {
	Connecter_pipes ();
	if (execvp (TabArg[0], TabArg) == -1) {
	    printf ("%s n'a pas marche.\n", msg);
	    exit (-1);
	}

    }
    else if (pid == -1) {
    	sprintf (msg, "fork: %s", sys_errlist[errno]);
    	Afficher (msg);
    }
}


	/************************************************************
	 PostScriptCB

	 Production d'un document PostScript
	 ************************************************************/
	
static void     PostScriptCB (w, client_data, call_data)
/****************************************/
    Widget          w;
    XtPointer       client_data,
                    call_data;
{
    char            msg[255];

    if (Changer_repertoire (Repertoire) == -1) {
	sprintf (msg, "%s: %s", Repertoire, sys_errlist[errno]);
	Afficher (msg);
	return;
    }
    if (PostScriptActif == True) {
        sprintf (msg, "%s (PID=%d) encore actif !", Pilote, PostScriptPid);
        Afficher (msg);
        return;
    }
    Supprimer_suffixe_tex ();
    sprintf (msg, "%s -o %s.ps %s", Pilote, Document, Document);
    Afficher (msg);
    Positionner_arguments (msg);
    PostScriptActif = True;
    if ((PostScriptPid = fork ()) == 0) {
	Connecter_pipes ();
	if (execvp (TabArg[0], TabArg) == -1) {
	    printf ("%s n'a pas marche.\n", msg);
	    exit (-1);
	}

    }
    else if (PostScriptPid == -1) {
    	sprintf (msg, "fork: %s", sys_errlist[errno]);
    	Afficher (msg);
        PostScriptActif = False;
    }
}


	/************************************************************
	 FaconnerCB

	 Execution de la commande de faconnage. Plusieurs processus
	 pouvant etre lances, un groupe de processus est cree
	 permettant d'agir globalement avec les signaux
	 ************************************************************/
	
static void     FaconnerCB (w, client_data, call_data)
/****************************************/
    Widget          w;
    XtPointer       client_data,
                    call_data;
{
    char            msg[255];

    if (Changer_repertoire (Repertoire) == -1) {
	sprintf (msg, "%s: %s", Repertoire, sys_errlist[errno]);
	Afficher (msg);
	return;
    }
    if (FaconneurActif == True) {
	sprintf (msg, "%s (PID=%d) encore actif !", Faconneur, FaconneurPid);
	Afficher (msg);
	return;
    }
    Reinitialiser_fenetre_interaction ();
    Supprimer_suffixe_tex ();
    sprintf (msg, "%s %s", Faconneur, Document);
    Afficher (msg);
    Positionner_arguments (msg);
    FaconneurActif = True;
    if ((FaconneurPid = fork ()) == 0) {
	Connecter_pipes ();
	if (execvp (TabArg[0], TabArg) == -1) {
	    printf ("%s est inaccessible.\n", Faconneur);
	    exit (-1);
	}
    }
    else if (FaconneurPid == -1) {
    	sprintf (msg, "fork: %s", sys_errlist[errno]);
    	Afficher (msg);
    	FaconneurActif = False;
    }
}


	/************************************************************
	 StatutCB

	 Interrogation de la file d'attente de l'imprimante
	 ************************************************************/
	
static void     StatutCB (w, client_data, call_data)
/****************************************/
    Widget          w;
    XtPointer       client_data,
                    call_data;
{
    int		    pid;
    char            msg[255],
                    arg[255];

    sprintf (msg, "%s %s%s", LPQ, ALPQ, Imprimante);
    Afficher (msg);
    
    sprintf (arg, "%s%s", ALPQ, Imprimante);

    if ((pid = fork ()) == 0) {
	Connecter_pipes ();
	if (execlp (LPQ, LPQ, arg, '\00') == -1) {
	    printf ("%s: %s.\n", msg, sys_errlist[errno]);
	    exit (-1);
	}
    }
    else if (pid == -1) {
    	sprintf (msg, "fork: %s", sys_errlist[errno]);
    	Afficher (msg);
    }
}


	/************************************************************
	 EditerCB

	 Execution de la commande d'edition de texte
	 ************************************************************/
	
static void     EditerCB (w, client_data, call_data)
/****************************************/
    Widget          w;
    XtPointer       client_data,
                    call_data;
{
    char            msg[255];
    int		    pid;

    if (Changer_repertoire (Repertoire) == -1) {
	sprintf (msg, "%s: %s", Repertoire, sys_errlist[errno]);
	Afficher (msg);
	return;
    }
    Supprimer_suffixe_tex ();
    if (Ressources_xlatex.editeur_avec_xterm == True)
	sprintf (msg, "xterm -e %s %s.tex", Editeur, Document);
    else
	sprintf (msg, "%s %s.tex", Editeur, Document);
    Afficher (msg);
    Positionner_arguments (msg);
    if ((pid = fork ()) == 0) {
	Connecter_pipes ();
	if (execvp (TabArg[0], TabArg) == -1) {
	    printf ("%s: %s.\n", msg, sys_errlist[errno]);
	    exit (-1);
	}
    }
    else if (pid == -1) {
    	sprintf (msg, "fork: %s", sys_errlist[errno]);
    	Afficher (msg);
    }
}


	/************************************************************
	 QuitterCB

	 Fin de l'application Xlatex.
	 Tous les processus lances encore actifs sont termines.
	 ************************************************************/
	
static void     QuitterCB (w, client_data, call_data)
/****************************************/
    Widget          w;
    XtPointer       client_data,
                    call_data;
{
    signal (SIGTERM, SIG_IGN);
    killpg (Pgid, SIGTERM);
    XtDestroyWidget (Toplevel);
    exit (0);
}

/* --- ACTIONS --- */

	/************************************************************
	 FocaliserACT

	 Entree de la souris dans un champ d'entree de texte.
	 Demarquage du pourtour du champ precedent
	 Marquage du pourtour du champ courant
	 Positionnement du focus
	 ************************************************************/
	
static XtActionProc FocaliserACT (wg, event, params, num_params)
/****************************************/
    Widget          wg;
    XEvent      *event;
    String         *params;
    Cardinal       *num_params;
{
    if (XtIsSensitive(wg)) {
	XtVaSetValues (Focus, XtNborderColor, CouleurDeFond, NULL);
	if (*num_params == 0) {
	    XtVaSetValues (wg, XtNborderColor, CouleurDeBordure, NULL);
	    Focus = wg;
	}
	XtSetKeyboardFocus (XtParent (wg), wg);
    }
    else
	ChampSuivantACT(wg, event, params, num_params);
    
    return (0);
}

    
	/************************************************************
	 ChampSuivantACT

	 Recherche du champ suivant dans le groupe de tabulation
	 Une fois trouve, focalisation sur celui-ci
	 ************************************************************/
	
static XtActionProc ChampSuivantACT (wg, event, params, num_params)
/****************************************/
    Widget          wg;
    XEvent      *event;
    String         *params;
    Cardinal       *num_params;
{
    ENTRY	    elem,
		    *elem_cherche;
    char	    *nom;
    int		     i;

    nom = XtName(wg);
    elem.key=nom;
    elem_cherche=hsearch(elem,FIND);
    i = *(int *)elem_cherche->data;
    FocaliserACT (TabGroup[i].wg,event,params,num_params);
    return (0);
}

    
	/***********************************************************
	 ControlACT

	 Entree d'une sequence d'interruption.
	 	^C -> envoi du signal SIGINT aux processus de faconnage
	 	^D -> envoi du signal SIGTERM aux processus de faconnage
	 ************************************************************/
	
static XtActionProc ControlACT (wg, event, params, num_params)
/****************************************/
    Widget          wg;
    XKeyEvent      *event;
    String         *params;
    Cardinal       *num_params;
{
    char            car;
    int             lg;

    /* Obtention du caractere frappe */
    lg = XLookupString (event, &car, 1, NULL, NULL);

    switch (car) {
    case 3:			/* Ctrl-C */
	kill (FaconneurPid, SIGINT);
	break;
    case 4:			/* Ctrl-D */
	kill (FaconneurPid, SIGTERM);
	break;
    }

    TamponEntree_lg = 0;
    XawTextSetInsertionPoint (Interaction_wg, POINT_INSERTION);

    return (0);
}


	/************************************************************
	 InsertACT

	 Entree d'un caractere dans la fenetre d'interaction.
	 Le caractere est memorise dans le tampon TamponEntree
	 ************************************************************/
	
static XtActionProc InsertACT (wg, event, params, num_params)
/****************************************/
    Widget          wg;
    XKeyEvent      *event;
    String         *params;
    Cardinal       *num_params;
{
    char            str[32];
    int             lg;
    register int    i;

    /* Obtention des caracteres frappes */
    lg = XLookupString (event, str, sizeof (str), NULL, NULL);

    strncat (TamponEntree, str, lg);
    TamponEntree_lg += lg;

    XawTextSetInsertionPoint (Interaction_wg, POINT_INSERTION);

    return (0);
}


	/************************************************************
	 DeleteACT

	 Correction de frappe dans la fenetre d'interaction.
	 Le tampon TamponEntree est mis a jour.
	 ************************************************************/
	
static XtActionProc DeleteACT (wg, event, params, num_params)
/****************************************/
    Widget          wg;
    XEvent      *event;
    String         *params;
    Cardinal       *num_params;
{
    /*
       On veille a ne pas corriger au dela des caracteres precedemment
       introduits.
    */
    if (TamponEntree_lg > 0)
	TamponEntree[--TamponEntree_lg] = '\00';

    return (0);
}


	/************************************************************
	 SendACT

	 Frappe d'un retour a la ligne dans la fenetre d'interaction.
	 Le contenu du tampon TamponEntree est envoye dans le pipe
	 Pipe_entree[1].
	 ************************************************************/
	
static XtActionProc SendACT (wg, event, params, num_params)
/****************************************/
    Widget          wg;
    XEvent      *event;
    String         *params;
    Cardinal       *num_params;
{
    /* Envoi de la commande */
    strcat (TamponEntree, "\n");
    TamponEntree_lg++;

    (void) write (Pipe_entree[1], TamponEntree, TamponEntree_lg);

    /*
       Reinitialisation de TamponEntree et mise a jour de la position dans la
       fenetre d'interaction
    */
    TamponEntree[0] = '\00';
    TamponEntree_lg = 0;

    return (0);
}


/*
 * ---------------------------------------------------------------------------
 * 				PROGRAMME PRINCIPAL
 * ---------------------------------------------------------------------------
 */
main (argc, argv)
/****************************************/
    int             argc;
    char           *argv[];
{
/*    fprintf (stderr, BANNER, VERSION);*/

    if ((Pgid = fork ()))
        exit (0);

/*
 * La, c'est un peu galere ! Il faut assurer que ce processus est leader
 * du groupe qu'il va dominer
 * Sur Sun (SunOS 4.x), setsid() ou setpgrp(0,0) serait tout indique ...
 */
 
#ifdef gould
    setpgrp (0, Pgid);
#else
    setsid ();
#endif /* gould */

    Initialiser_pipes ();
    Initialiser_Xt (argc, argv);

    Creer_widgets ();
    Creer_popup_imprimer ();

    Installer_accelerateurs ();

    XtRealizeWidget (Toplevel);

    XtAppMainLoop (Xlatex_app_con);
}