/*
 ++
 Nom
		EDIT_FONTES.C

 Description
 	Programme pour generer un fichier PXL a partir de fichiers existant

	 D'apres le programme FFC.WEB de DEC

 Utilisation
		edit_fontes [fichier_resultat] [fichier_source]

 Creation

    Version 0.0.a, 10 Janvier 1986 - JNA (1.0)
	Lecture de fichiers PXL, transfert de certains caracteres dans un
	buffer en memoire, eventuellement modification de caracteres de
	ce buffer et sauvetage avec un nouveau nom du fichier resultat
	Au passage, tenu d'un journal pour reprendre en cas d'erreur
	(Note : Le fonctionnement en mode RECOVER n'est pas prevu)


 Modification
	15 Janvier 1986 - JNA (2.0)	- Version 0.0.b
		Reecriture en Pascal.

	21 Janvier 1986 - JNA (3.0)	- Version 0.1
		Transcription en C.

	3 Fevrier 1986 - JNA
		Permutation des fichiers resultats et sources
		Possibilite d'ignorer les caracteres non definis en mode
			TYP.

 --
*/


#include <stdio.h>
#include <ctype.h>


#define	banner "Modification des PXL, Version 0.1"
#define prompt "EDIT_FONTES> "

	/* Commandes */

#define MAX_INPUT 128		/* Taille du buffer de commande	*/

char inline[MAX_INPUT]; 	/* Ligne de commande		*/
char *command;			/* Pointe la commande utilisateur*/

enum  command_type {
	save,  	 		/* Sauve le fichier modifie */
	help,    	      	/* Mode d'emploi */
	keep,    		/* Conserve un ou plusieurs caracteres */
	edit,    		/* Modifie un des caracteres conserves */
	modif,			/* Modifie les parametres d'un caractere */
	modfile,		/* Modification des parametres du fichier */
	load,   		/* read .{PXL} format file */
	typ,    		/* typ .{PXL} character rasters */
	typlong,    		/* type a longword from the .{PXL} file */
	typword,    		/* type a word from the .{PXL} file */
	compress,   		/* Compression du buffer .{PXM} */
	typmod,   		/* Affiche un caractere du buffer .{PXM} */
	dmpdict,    		/* Dump le dictionnaire .{PXM} - JNA (2.1) */
	cm_exit,			/* leave MODPXL */
	nonesuch,               /* there is no such command */
	illegal			/* Illegal command	*/
      		};
enum command_type verb;	   		/* Verbe de commande		*/

char	*table_command[] = {
		"save", "help", "keep", "edit", 
		"modif", "modfile", "load", "typ", "typlong",
		"typword", "compress", "typmod", "dmpdict", "exit", 
		"nonesuch", 
		""			/* Indication de fin de table	*/
	};

#define no_command	(strlen(command) == 0)


	/* Buffer des caracteres	*/

#define	pxl_blocks	512
#define nb_blocks	512

#define pxl_buf_size	(pxl_blocks*nb_blocks)

typedef char PXL_BUF_TYPE[pxl_buf_size];

	/* Definition de structures - Utiliser pour les traductions */
	/*	Dans l'hyphothese de la translation des octets sous VMS*/

union TYPE_LONG {
	     char c[4];
	long  int l;
	};

union TYPE_WORD {
	     char c[2];
	short int w;
	};

	int pxl_len;
			     	/* Buffer de travail des donnees */
	PXL_BUF_TYPE pxl_buf;
				/* Buffer de travail - Raster modifies */
	PXL_BUF_TYPE pxm_raster;
				/* Dictionnaire temporaire */
	char pxm_dict[16*128+4*5];

	int ilp,istart,illen;
	int pxm_char,		/* Position des prochains caracteres	*/
	    pxl_first_char,
	    pxl_last_char;

	int pxm_ras = 4;	/* Position du prochain raster		*/

	FILE *pxl_file;			/* Fichier PXL - En entree	*/
	char pxl_name[132];
	int dsize, mag;
	double rsize;
               
	int def_start, ras_start;
	int x_offset, y_offset, tfm_width;
	int i,j,k,l,m,n; 		 /* scratch variables */

	int dest_char, first_char, last_char;

	int row, column;
	int len_raster;

	FILE *outfile;	   		/* Fichier modifie - En sortie */
	char output_name[132];

/*	Constante multiplicative des formats PXL	*/

#define	deux_puissance_20	0x100000

/*                                                    
		=========================================
		|	PROCEDURES INDEPANDANTES	|
		=========================================
*/

/*
 Command input. The user's command lines are read into a buffer called
|inline|. The variables |ilp| and |istart| are used to point into it,
while |illen| keeps track of its length. The variable |verb| holds an
integer code representing the command verb.
*/
            
#define	the_char	inline[ilp]


/*
Each command consists of a verb, a space, and arguments. The command
handling procedure itself parses the arguments from |inline|. The verbs are
converted into integer values by the function |command_verb|. That
function is now coded inefficiently; it should eventually be implemented
using a hash table.                                      
*/

/*
To pick out the command verb, we frequently use two parsing macros,
|skipb| and |skipnb|, which skip over blanks and non-blanks respectively in
the |inline| string, advancing the index variable |ilp| as they go. 
*/
skipb()
{
	while ((ilp <= illen) && isspace(the_char))
		ilp = ilp+1;
}
skipnb()
{
	while ((ilp <= illen) && !isspace(the_char))
		ilp = ilp+1;
}                             


#define	pxl_def_start(c)	(pxl_len - 4*517 + 16*c)

/*
	Routines de conversion entre les buffers en octets et des entiers
*/

pxl_to_long(c)
int c;                        
{
	union TYPE_LONG mot;
	register i;

	for (i=0; i<4; i++)
		mot.c[i] = pxl_buf[c-i+3];

	return (mot.l);
}

pxl_to_word(c)
int c;
{
	union TYPE_WORD mot;
	register i;                      

	for (i=0; i<2; i++)             
		mot.c[i] = pxl_buf[c-i+1];

	return (mot.w);
}

pxm_to_long(c)
int c;
{
	union TYPE_LONG mot;
	register i;

	for (i=0; i<4; i++)
		mot.c[i] = pxm_raster[c-i+3];

	return (mot.l);
}

pxm_to_word(c)
int c;
{
	union TYPE_WORD mot;
	register i;

	for (i=0; i<2; i++)
		mot.c[i] = pxm_raster[c-i+1];

	return (mot.w);
}

dict_to_long(c)
int c;
{
	union TYPE_LONG mot;
	register i;

	for (i=0; i<4; i++)
		mot.c[i] = pxm_dict[c-i+3];

	return (mot.l);
}

dict_to_word(c)
int c; 
{
	union TYPE_WORD mot;
	register i;

	for (i=0; i<2; i++)
		mot.c[i] = pxm_dict[c-i+1];

	return (mot.w);
}

word_to_dict (offset, value)
int offset, value;
{                                           
        pxm_dict[offset] = value / 256;
        pxm_dict[offset+1] = value % 256;
	if (dict_to_word(offset) != value) 
 		printf(">>> La fonction WORD_TO_DICT est incorrecte\n");
}

long_to_dict (offset, value)
int offset, value;
{
        word_to_dict(offset, value / (256*256));    /* Attention a l'ordre*/
        word_to_dict(offset+2, value % (256*256));
	if (dict_to_long(offset) != value) 
		printf(">>> La fonction LONG_TO_DICT est incorrecte");
}

long_to_pxm (offset, value)
int offset, value;
{
	int i;
	int low_value, high_value;

	low_value = value / (256*256);
	high_value= value % (256*256);
	pxm_raster[offset+0] = low_value  / 256;
	pxm_raster[offset+1] = low_value  % 256;
	pxm_raster[offset+2] = high_value / 256;
	pxm_raster[offset+3] = high_value % 256;
	if (pxm_to_long(offset) != value)
	   {
		printf(">>> LONG_TO_PXM - Erreur pour l'offset %d\n",
						offset);
		printf("    Value       :%d\n",value);
		printf("    PXM_TO_LONG :%d\n",pxm_to_long(offset));
		for (i=offset; i<offset+3; i++) 
			printf("    RASTER [%d]  :%d\n",i, pxm_raster[i]);
	   }
}

/*
 *	GET_WORD
 *		Place un mot de la ligne de commande la variable COMMAND.
 *		Il n'y a pas de transfert des caracteres, mais redirection
 *		de pointeurs.
 */

get_word()
{
	command = NULL;			/* Reinitialise	*/
	skipb(); 			/* Cherche le debut du mot	*/
	command = &inline[ilp];		/* COMMAND est un pointeur dirige
						sur le debut du verbe 'commande'
						(dans le buffer d'input)*/
	skipnb();     			/* Cherche la fin  du mot	*/
	inline[ilp++] = '\0';		/* Marque la fin du verbe 	*/
}

/*
 *	GET_COMMAND
 *		Extrait un mot de la ligne de commande et le met en minuscule
 */
get_command()
{
	register char *pt_c;                                            

	get_word();   				/* Extrait un mot	*/

	for (pt_c=command; *pt_c; ++pt_c)	/* Transcrit en minuscule */
	   {
		*pt_c=tolower(*pt_c);
	   }

}
/*
 *	GET_ONE_CHAR
 *
 *		Extraction d'un caractere de la ligne de commande
 *		Retourne sa valeur entiere
 */
get_one_char()
{
	get_word();		/* Extrait le prochain mot de la ligne */

	if (*command == '\'')		/* Forme ASCII	*/
		return(*(++command));
	else
		return(atoi(command));
}    

/*
 *	COMMAND_VERB
 *
 *		Extrait le code de la commande
 */

enum command_type
command_verb()
{
	register enum command_type n;

 	get_command();                                      

	for (n=0; *table_command[n]; n++)	/* Sortie : commande Nulle */
		if (strcmp(table_command[n], command) == 0)
			return(n);

	return(illegal);
}


/*
 La fonction COPY_CHARACTER est destinee a copier un caractere depuis
le buffer PXL vers le buffer PXM. Elle est utilisee par |KEEP| et |COMPRESS|.
*/

copy_character(src_char, compress_flag)
int src_char, compress_flag;
{                               
      int def_start, ras_start, row, column, len_raster; 
      int k, l; 

            /* Debut des rasters sources */
      def_start = pxl_def_start(src_char);
      ras_start = 4 * pxl_to_long(def_start+8);

      if (ras_start != 0) 
	 {	/* 0 : Caractere indefini*/
           if ((ras_start<4) && (ras_start>pxl_len)) 
              {
	        return(FALSE);
	      }
           else
	      {
                        
                  /* Calcul des dimensionss de la matrice de points*/
	            row = pxl_to_word(def_start+2);
	            column = pxl_to_word(def_start);

                  /* Calcul du nombre de mots de 32 bits en largeur*/
	            k = column / 32;
	            if (k*32 != column)
				k=k+1;

                  /* Longueur en octet de la matrice */
  	            len_raster = k*4*row;
		    if (pxm_ras+len_raster > pxl_buf_size)
			{
				printf("Buffer temporaire sature\n");
				return(FALSE);
			}

                  /* Recopie des rasters */
	            for (l=0; l<len_raster; l++) 
	               pxm_raster[pxm_ras+l] = pxl_buf[ras_start+l];

                  /* Recopie du dictionnaire */
	            k = 16 * pxm_char;
	            for (l=0; l<16; l++) 
	               pxm_dict[k+l] = pxl_buf[def_start+l];

                  /* Correction de l'adresse des routines dans le dictionnaire*/
	            long_to_dict(k+8, pxm_ras / 4);

                  /* Mise a jour des pointeurs */
	            pxm_ras = pxm_ras + len_raster;
	            pxm_char = pxm_char + 1;

	            return (TRUE);
	   }
	}                
      else
	{
		/*
		 *	Ce n'est pas une erreur si le caractere est
		 *		non defini si COPY_CHARACTER est appele
		 *		par DO_COMPRESS
		 */
		if (compress_flag)
		   {
		         pxm_char = pxm_char + 1;	/* Caractere suivant */
		         return (TRUE);
		   }
		else
		   {
			printf("Caractere %d non defini\n",src_char);
			return(FALSE);
		   }
	}
}

/*                      
La compression du dictionnaire est utile lorsque trop de caracteres ont
ete ecrases, entrainant la formation de rasters 'perdus'. La fonction 
DO_COMPRESS_PXM est appelable par la commande COMPRESS. Elle est appelee 
automatiquement lors du sauvetage (SAVE).
 La compression est executee en deux temps: Transfert des donnees brutes
vers le buffer PXL, puis copie de PXL vers PXM en utilisant la fonction
COPY_CHARACTER. La compression detruit le buffer PXL.
*/

do_compress_pxm()      
{
	int l;
	int flag;

		/* Transfert des rasters PXM dans PXL */        
	for (l=4; l<pxm_ras; l++) 
	    {
		pxl_buf[l] = pxm_raster[l];
	     	pxm_raster[l] = 0;			/* Remise a zero */
	    }
        
		/* Copie du dictionnaire dans PXL */
	for (l=0; l<(16*128); l++) 
	    {
		pxl_buf[pxm_ras++]=pxm_dict[l];
	     	pxm_dict[l] = 0;			/* Remise a zero */
	    }

		/* Redefinition des pointeurs */
	pxl_len = pxm_ras + 4*5;
  	pxm_ras = 4; pxm_char = pxl_first_char =  pxl_last_char = 0;

		/* Reconstruction du buffer PXM et du dictionnaire */
	flag = TRUE;

	l = 0;
	while ((l<=127) && flag) 
	   {
		flag = copy_character(l, TRUE);
		l = l+1;
	   }
	if (!flag) 
		printf("COMPRESS echoue au caractere %d\n",l-1);
	return(flag);
}


/*                                      
	=========================================
	|	DEBUT DU PROGRAMME PRINCIPAL	|
	=========================================
*/

/*
The main loop of the program is a loop of reading and executing commands:
*/
main(argc, argv)
int argc;
char *argv[];
{                     
    printf("%s\n\n",banner); 
    if (argc > 2) 
		cmd_load(argv[2]);        
    if (argc > 1) 
		strcpy(output_name, argv[1]);

    for (;;)
	{
	    printf("%s",prompt);
				/* Permet de lire une ligne vide */
	    if (gets(inline) == NULL)
		{
			exit();
		}
	    
	    if (strlen(inline) <= 0)
		{
			continue;
		}
	    if (strlen(inline) >= MAX_INPUT)
		{
			printf("Ligne de commande trop longue\n");
			continue;
		}
	    strcat(inline, " ");                /* ? */
	    ilp = 0;
	    illen = strlen(inline);
	    switch (command_verb())
		{
		    case illegal:
			printf("Commande inconnue : %s (%s)\n",
						command,&inline[ilp]);
			break;             
		    case nonesuch :
			break;
		    case load :
			cmd_load("");
			break;
		    case typ :
			cmd_typ();
			break;
		    case typmod :
			cmd_typmod();
			break;
		    case typlong :
			cmd_typlong();
			break;
		    case typword :
			cmd_typword();
			break;
		    case dmpdict :              
			cmd_dmpdict();
			break;
		    case keep :
			cmd_keep();
			break;
		    case compress :
			cmd_compress();
			break;
		    case edit :
			cmd_edit();
			break;
		    case modif :
			cmd_modif();
			break;
		    case modfile :
			cmd_modfile();
			break;
		    case save :
			cmd_save();
			break;
		    case help :
			cmd_help();
			break;
/*                                         
 Leaving the program. If the user types an exit command, we leave:
*/
		    case cm_exit :
			exit();
		}
	}
}

/*
Reading PXL format files. The .{PXL} format is simple. Again we read
the entire file into a single large buffer: 
*/                                          

cmd_load(file)
char *file;
   {
	if (strlen(file) == 0)
	   {
		get_word();		/* Command : Nom du fichier	*/
		    			/* Eventuellement - Extension 	*/
		if ( no_command )
		   {
		 	printf("Il manque le nom du fichier a charger\n");
		  	return;
		   }
	   }
	else
		command = file;

	if ((pxl_file = fopen(command,"r","rfm=fix","mrs=512")) 
			      			== NULL)
	   {
		printf("Acces impossible au fichier %s\n",command);
		return;
	   }
	else
	    	strcpy(pxl_name, command);
                                     
/*
The .{PXL} file is read into inline, line by line, and copied into the
pxl_buf: 
*/
	pxl_len=0;
	while ((pxl_len < pxl_buf_size) &&
		fread(&pxl_buf[pxl_len], pxl_blocks, 1, pxl_file) > 0)
			pxl_len += pxl_blocks; 
	fclose(pxl_file);

/*                                                     
As was the case for the LN03 format file, we would also like to
checks the .{PXL} file just read in, to warn the user about
anomalies. 

On VMS systems, .{PXL} files are usually padded with extra longwords at
the } so their length is a multiple of 512. Thus, we search backwards
from the } of the file, looking for the ID longword (value 1001), which
marks the real } of the file. We only search through the last 512 bytes,
however. 
*/
                                   
	if (pxl_len % 4 != 0) 
	   {                             
		printf("Le fichier PXL n'a pas une longueur multiple de 4\n");
	   	printf("    PXL_LEN %d\n",pxl_len);
	   }
	if (pxl_to_long(0) != 1001)
	   {    
		printf("Identificateur initial de format PXL incorrecte\n");
	    	printf("Theorique %d - Lu %d\n",1001,pxl_to_long(0));
	   }
	i = pxl_len-4;
	while (i >= pxl_len-512)
	   {
		if (pxl_to_long(i) == 1001)
		   {
		    	pxl_len = i+4;
		    	i = -1;
		    }
		else
			i = i-4;
	   }                                                       

	if (pxl_len < 16)
	   {
	    	printf("Fichier PXL trop petit\n");
	   	printf("    PXL_LEN %d\n",pxl_len);
	   }

	if (pxl_to_long(pxl_len-4) != 1001)
	   {
		printf("Identificateur final de format PXL incorrecte\n");
	    	printf("Theorique %d - Lu %d\n",1001,pxl_to_long(pxl_len-4));
	   }

	/* Eventuellement - Controler entre deux fichiers */

	mag = pxl_to_long(pxl_len - 16);
	dsize = pxl_to_long(pxl_len - 12);

	printf("MAG %d - DSIZE (%d, %f)- PXL_LEN %d\n",
				mag,dsize, ((double)dsize)/deux_puissance_20,
				pxl_len);

   }    

	char CTRL_Z_KEY =  26; 		/* Arret de l'affichage en continue */
	char EXIT_KEY   = 290;		/* Arret de l'affichage en continue */
	char RET_KEY    =  13;		/* Caractere suivant 		    */

cmd_typ()
   {                                                
	int first_char, last_char;
	char rep;

	first_char = get_one_char();
	if (no_command)
	   {
		first_char = last_char = pxl_first_char;
	   }
	else
	   {
	    	if ((first_char < 0) || (first_char > 127))
		   {
			printf("Caractere inconnu %d\n",first_char);
			return;
		   }
		last_char = get_one_char();
		if (no_command)
		   {
			last_char = first_char;
		   }
	    	else if ((last_char < 0) || (last_char > 127))
		   {
			printf("Caractere inconnu %d\n",last_char); 
			return;
		   }
	   }

	for (j=first_char; j<=last_char; j++)
	    { 
		def_start = pxl_len - 4*517 + 16*j;
		ras_start = 4*pxl_to_long(def_start+8);
		if (ras_start <= 0)
		   {
			printf("Caractere non defini %d  : ",j); 
			if (gets(inline) == NULL)
			   {
				return;
			   }
			else
				continue;
		   }

		if (ras_start > pxl_len)
		   {
			printf("Rasters en dehors du fichier %d - %d  : ",
							ras_start,pxl_len);
			if (gets(inline) == NULL)
			   {
				return;
			   }
			else
				continue;
		   }
		column = pxl_to_word(def_start);    
       		row = pxl_to_word(def_start+2);
	    	rep=affiche_caractere(&pxl_buf[ras_start],&column,&row);
		if (rep == CTRL_Z_KEY || rep == EXIT_KEY)
			   	return;
	   }
}
/*
Controle des caracteres sauves. Affiche un caractere du buffer temporaire
*/

cmd_typmod()
   {
	int first_char, last_char;
	char rep;

	first_char = get_one_char();
	if (no_command)
	   {
	    	if (pxm_char == 0)
		   {
			printf("Caractere non definie\n"); 
			return;
		   }
		else
			first_char = pxm_char - 1;
	   }
	else
	   {
	    	if ((first_char < 0) || (first_char > 127))
		   {
			printf("Caractere inconnu %d\n",first_char); 
			return;
		   }
		last_char = get_one_char();
		if (no_command)
		   {
			last_char = first_char;
		   }
	    	else if ((last_char < 0) || (last_char > 127))
		   {
			printf("Caractere inconnu %d\n",first_char); 
			return;
		   }
	   }
	for (j=first_char; j<=last_char; j++)
	    {
		i = j*16;
		ras_start = 4*dict_to_long(i+8);
		if (ras_start <= 0)
		   {
			printf("Caractere indefini %d  : ",j);
			if (gets(inline) == NULL)
			   {
				return;
			   }
			else
				continue;
		   }

	    	if (ras_start > pxm_ras)
		   {
			printf("Rasters en dehors du fichier (pxm_ras = %d ) : ",
							pxm_ras);
			if (gets(inline) == NULL)
			   {
				return;
			   }
			else
				continue;
		   }
	    	column = dict_to_word(i);    
	    	row = dict_to_word(i+2);
		rep=affiche_caractere(&pxm_raster[ras_start],&column,&row);
		if (rep == CTRL_Z_KEY || rep == EXIT_KEY)
				return;
	   }
}
                 
/*
Typing row data from the file. For preliminary debugging purposes, it is
useful to have the ability to type row data from a font file. This is the
purpose of the following simple code: 
*/

cmd_typlong()
    {
	i = get_one_char();
	if ((i >= 0) && (i < pxl_len))
		printf("Position %d : %d\n",i,pxl_to_long(i));
	else     
		printf("Position hors du fichier\n"); 
    }

cmd_typword()
   {
    	i = get_one_char();
    	if ((i >= 0) && (i < pxl_len)) 
		printf("Position %d : %d\n",i,pxl_to_word(i));
    	else 
		printf("Position hors du fichier\n");
   }


/*
Dump le dictionnaire.
Si un nombre est indique, le dump commence a partir de ce caractere
*/

cmd_dmpdict()
   {
 	first_char = get_one_char();
	last_char = get_one_char();
	if ((first_char<0) || (last_char<0))
	   {
		printf("Caractere inconnu %d ou %d\n",first_char,last_char); 
		return;
	   }
	if (last_char < first_char)
		last_char = first_char;

	printf("Controle du dictionnaire de %d a %d\n",first_char,last_char);

	for (j=first_char; j<=last_char; j++)
	    {
		i = j*16;
		column = dict_to_word(i);
		row = dict_to_word(i + 2);
		ras_start = 4*dict_to_long(i + 8);       
		x_offset = dict_to_word(i + 4);
		y_offset = dict_to_word(i + 6);
		tfm_width = dict_to_long(i+12);
                                                          
		printf("-------------------\n");
		printf("Caractere <%d>\n",j);
		printf("	Code ");
	      	if ((32 <= j) && (j<127)) 
			printf("%c\n",j);
		else if (j==127) 
			printf("DEL\n");
		else
			printf("^%c\n",'A'+j-1);

		if (ras_start <= 0)
		   {
			printf("NON DEFINI\n");
			continue;
		   }          

		printf("	Ligne %d -- Colonne %d\n",row,column);
		printf("	X offset %d -- Y offset %d\n",x_offset,
			 				y_offset);
		printf("	Raster Start %d\n",ras_start);
		printf("	TFM WIDTH    %d -- %f\n", tfm_width, 
					((double) dsize) / deux_puissance_20);
		printf("\n");
   	   }
	printf("Prochaine position libre dans le buffer %d - Max %d\n",
				pxm_ras, pxl_buf_size);
    }

/*              
Transfert des caracteres.
Conserve un ou plusieurs caracteres du fichier PXL dans un buffer de
travail PXM.
 La construction du fichier PXM se fait en 3 etapes. Dans un premier temps,
le buffer PXM est initialise. Le pointeur RAS_PXM donne la position de depart
dans le buffer. Le compteur courant de caracteres est mis a zero.
 Dans la phase 
KEEP proprement dite, les rasters sont transferer dans le
buffer et le dictionnaire est mis a jour.
 Enfin, au moment du sauvetage, le dictionnaire est transfere et le fichier
PXM est complete avec les differentes informations necessaire au format
PXM (Checksum, identificateur,...).
*/

/*
L'initialisation est faite lors du premier passage dans ce module. Aucun
controle n'est fait sur la presence ou non d'un ancien caractere dans le
dictionnaire. Ainsi, des rasters anterieurs peuvent tere ecrases en transferant
de nouveaux caracteres. Ces rasters sont 'perdus'. Ils ne sont plus 'pointes'
par le dictionnaire. Il est possible de les eliminer par l'operation de
compression.
*/

cmd_keep()
   {
	register trs_char;

    	first_char = get_one_char();	/* Qui charge au passage COMMAND*/
	if ( no_command )
	   {
		first_char = last_char =  pxl_last_char;
		dest_char = pxm_char;
	   }
	else
	   {                                  
		last_char = get_one_char();
		if (strcmp(command,"-") == 0)
		   {
					/* Effectivement un transfert groupe*/
			last_char = get_one_char();
			dest_char = get_one_char();
		   }
		else
		   {
					/* Transfert de 1 caractere */
			dest_char = last_char;
			last_char = first_char;
	  	   }

		/* Le derniere appel a GET_ONE_CHAR charge COMMAND */
		if ( ! no_command )
		   {   
		    	pxm_char = dest_char;	/* Redefinition	*/
		   }
	   }

	     	/* Transfert des rasters et actualisation du dictionnaire*/

	pxl_first_char = first_char;
	pxl_last_char = last_char+1;

	for (trs_char= first_char; trs_char<=last_char; trs_char++) 
	    {
	     	printf("Transfert du caractere %d en %d\n",trs_char,pxm_char);
		if ( ! copy_character(trs_char, FALSE))
		   {
 		       	printf("Commande KEEP abandonnee\n");
			return;
		   }
	    }
   }


/*
Compression du buffer PXM. Permet d'eliminer des rasters 'perdus'.
*/

cmd_compress()
   {
	if ( ! do_compress_pxm())
	   {
		printf("Commande COMPRESS abandonnee\n");
		return;                                                     
	   }
	else
	   {
		printf("Prochaine position libre dans le buffer %d - Max %d\n",
				pxm_ras, pxl_buf_size);
		printf("ATTENTION --- La commande COMPRESS a ecrase %s\n",
					pxl_name);
	   }
   }

/*
Edition de caracteres. Modifie un des caracteres conserves
*/

cmd_edit()
   {
	register r;          
	int first_char, temp;
	char rep[8];

 	first_char = get_one_char();
	if ( no_command )
	   {
	    	if (pxm_char == 0)
		   {
			printf("Caractere inconnu\n"); 
			return;
		   }
		else
			first_char = pxm_char - 1;
	   }
	else
	   {
	    	if ((first_char < 0) || (first_char > 127))
		   {
			printf("Caractere inconnu %d\n",first_char); 
			return;
		   }
	   }
	i = first_char * 16;
    	ras_start = 4*dict_to_long(i+8);
	if (ras_start <= 0)
	   {
		printf("Caractere indefini %d\n",first_char); 
		return;
	   }

    	if (ras_start > pxm_ras)
	   {                            
		printf("Rasters hors du fichier\n");
		return;
	   }
    	column = dict_to_word(i);    
    	row = dict_to_word(i+2); 

	/*
	 *	Modifie un caractere et le recopie a la suite dans le
	 *	buffer.
	 */
	r = pxm_ras;
	printf("Edition du caractere %d\n",first_char);
	edit_caractere(&pxm_raster[ras_start], 
    			&column, &row, &pxm_raster[pxm_ras], &pxm_ras);

	printf("Caractere edite : %d\n",first_char);

    	word_to_dict(i, column);
    	word_to_dict(i+2, row);
	long_to_dict(i+8, r/4);		/* Origine du caractere	*/

	for(;;)
	  {
		printf("        Colonne : %d\n", dict_to_word(i) );
		printf("          Ligne : %d\n", dict_to_word(i+2) );
		printf("    Offset en X : %d\n", dict_to_word(i+4) );
		printf("    Offset en Y : %d\n", dict_to_word(i+6) );
		rsize = ((double)dict_to_long(i+12)) / deux_puissance_20;
		printf("        Fenetre : %d -- %f\n", 
					dict_to_long(i+12), rsize);

		printf("\nVoulez vous modifier \n");
		printf("      l'offset en X ou Y (X,Y), ou la fenetre (F,R) :");

		if (gets(rep) == NULL || strlen(rep) == 0)
			break;
		else
		   {
			rep[0] = tolower(rep[0]);
			if (rep[0] == 'x' || rep[0] == 'y' || 
					rep[0] == 'f' || rep[0] == 'r')
			   {
		    		printf("Entrez la nouvelle valeur : ");
				switch (tolower(rep[0]))
				   {
			       		case 'x' :
						scanf("%d", &temp);
						word_to_dict(i+4, temp);
						break;
					case 'y' :
						scanf("%d", &temp);
						word_to_dict(i+6, temp);
						break;
					case 'f' :
						scanf("%d", &temp);
		 				long_to_dict(i+12,temp);
						break;
					case 'r' :
						scanf("%f", &rsize);
						temp = rsize *
							   deux_puissance_20;
		 				long_to_dict(i+12, temp);
						break;
				   }
				getchar();	/* Probleme du CR	*/
			   }
		   }
	    }
   }

/*
 *	Modification des parametres d'un caractere
 */
cmd_modif()
{
	int first_char, temp;
	char rep[8];

 	first_char = get_one_char();
	if ( no_command )
	   {
	    	if (pxm_char == 0)
		   {
			printf("Caractere inconnu\n"); 
			return;
		   }
		else
			first_char = pxm_char - 1;
	   }
	else
	   {
	    	if ((first_char < 0) || (first_char > 127))
		   {
			printf("Caractere inconnu %d\n",first_char); 
			return;
		   }
	   }
	i = first_char * 16;
    	ras_start = 4*dict_to_long(i+8);
	if (ras_start <= 0)
	   {
		printf("Caractere indefini %d\n",first_char); 
		return;
	   }

    	if (ras_start > pxm_ras)
	   {                            
		printf("Rasters hors du fichier\n");
		return;
	   }

	printf("Modification du caractere %d\n",first_char);

	for(;;)
	  {
		printf("        Colonne : %d\n", dict_to_word(i) );
		printf("          Ligne : %d\n", dict_to_word(i+2) );
		printf("    Offset en X : %d\n", dict_to_word(i+4) );
		printf("    Offset en Y : %d\n", dict_to_word(i+6) );
		rsize = ((double)dict_to_long(i+12)) / deux_puissance_20;
		printf("        Fenetre : %d -- %f\n", 
					dict_to_long(i+12), rsize);

		printf("\nVoulez vous modifier \n");
		printf("      l'offset en X ou Y (X,Y), ou la fenetre (F,R) :");

		if (gets(rep) == NULL || strlen(rep) == 0)
			break;
		else
		   {
			rep[0] = tolower(rep[0]);
			if (rep[0] == 'x' || rep[0] == 'y' || 
					rep[0] == 'f' || rep[0] == 'r')
			   {
		    		printf("Entrez la nouvelle valeur : ");
				switch (tolower(rep[0]))
				   {
			       		case 'x' :
						scanf("%d", &temp);
						word_to_dict(i+4, temp);
						break;
		/*
		 *	Cette valeur semble etre la position du haut de la
		 *	matrice par rapport a la ligne 0 de reference.
		 *	Pour la lettre H, cette valeur est de :
		 *	Pour la lettre -, cette valeur est de :
		 *	Pour la lettre _, cette valeur est de :
		 */
					case 'y' :
						scanf("%d", &temp);
						word_to_dict(i+6, temp);
						break;
					case 'f' :
						scanf("%d", &temp);
		 				long_to_dict(i+12,temp);
						break;
					case 'r' :
						scanf("%f", &rsize);
						temp = rsize *
							   deux_puissance_20;
		 				long_to_dict(i+12, temp);
						break;
				   }
				getchar();	/* Probleme du CR	*/
			   }
		   }
	    }
}

/*
 *	Modification des parametres du fichier
 */
cmd_modfile()
{
	register tmp;

	printf("Magnification actuelle %d - Entrez la nouvelle valeur : ",mag);
	if (gets(inline) == NULL)
	   {
		printf("Parametres generaux non modifies\n");
		return;
	   }
	tmp = atoi(inline);
	if (tmp <= 0)
	   {                                       
		printf("Valeur incorrecte (%d)\n",tmp);
		printf("Parametres generaux non modifies\n");
		return;
    	   }
	else
		printf("Nouvelle Magnification %d\n",tmp);

	rsize = dsize / deux_puissance_20;
	printf("Dsize actuelle %f - Entrez la nouvelle valeur : ",rsize);
	if (gets(inline) == NULL)
	   {
		printf("Parametres generaux non modifies\n");
		return;
	   }

	sscanf(inline,"%f",&rsize);
	rsize = rsize * deux_puissance_20;
	if (rsize <= 0.0)
	   {
		printf("Valeur incorrecte (%f)\n",rsize);
		printf("Parametres generaux non modifies\n");
		return;
	   }
	else
		printf("Nouvelle Dsize %f\n",rsize/((double)deux_puissance_20));
                                                        
	mag = tmp;
	dsize = rsize;
}

/*     
Sauvetage. Sauve du fichier modifie dans un fichier, au format PXL.
*/

/*
Le sauvetage se fait simplement en sortant les octets du buffer temporaire
dans outfile.                              
*/

cmd_save()
   {                                              
	register n, start_dict;
	char rep[8];

    	get_word();
	if ( no_command )
	   {
		if (strlen(output_name) != 0)
		   {
		    	printf("Fichier de sortie %s ([O],N) : ",
							output_name);
			gets(rep);
			if (rep[0] == 'N' || rep[0] == 'n')
			  {
				printf("Il manque le nom du fichier\n");
				return;
			   }
			else
				command=output_name;
		   }
		else
		  {
			printf("Il manque le nom du fichier\n");
			return;
		   }
	   }

	if ((outfile=fopen(command,"w","rfm=fix","mrs=512", "dna = PXM")) 
							== NULL)
	   {
		printf("Impossible d'ouvrir %s\n",command);
		return;
    	   }
	else if (command != output_name)
		strcpy(output_name, command);

		/* Compression du fichier PXM */

	if ( !do_compress_pxm())
	   {
		fclose(outfile);
		printf("La commande SAVE echoue\n");
		return;
	   }
                 
		/* Complement du fichier PXM */

	/*  Transfert le dictionnaire dans PXM */

	start_dict = pxm_ras;

	for (l=n=0; l<128; l++)
		for (k=0; k<16; k++)
			pxm_raster[pxm_ras++]=pxm_dict[n++];

		/* Mise en place des info generales */

		/* Check sum : apparament pas utiliser par FFC */
	long_to_pxm (pxm_ras, 0);		pxm_ras += 4;
	long_to_pxm (pxm_ras, mag);		pxm_ras += 4;
	long_to_pxm (pxm_ras, dsize);		pxm_ras += 4;
	long_to_pxm (pxm_ras, start_dict);	pxm_ras += 4;

			/* Ident PXL */

	long_to_pxm (pxm_ras, 1001);		pxm_ras += 4;
	long_to_pxm (0, 1001);


		/*  Controle de la longueur du fichier */

	if ((pxm_ras % 4) != 0)
	   {
		fclose(outfile);
		printf("Le fichier PXM n'a pas une longueur multiple de 4\n");
		printf("La commande SAVE echoue\n");
		return;
       	   }

		/* Controle des identifieurs */

	if (pxm_to_long(pxm_ras-4) != 1001)
	   {
		printf(">>> Identificateur de format PXL final incorrecte\n");
	   }
	if (pxm_to_long(0) != 1001)
	   {
		printf(">>> Identificateur initial de format PXL incorrecte\n");
	   }

		/* Reset de la fin du buffer */
		/* 	Plus net	*/

	for (l=pxm_ras%512; l<512; l++)
		pxm_raster[pxm_ras+l]=0;

		/* Calcul du nombre de bloc disques (512 octets) */

	for (l= 0; l<pxm_ras; l += pxl_blocks)
	    {
		k = fwrite(&pxm_raster[l], pxl_blocks, 1, outfile);
	    }

    	fclose(outfile);
	printf("Fichier %s sauve\n",output_name);
	printf("ATTENTION --- La commande SAVE a ecrase %s\n",
					pxl_name);

   }

/*
Aide. Mode d'emploi en ligne
*/
cmd_help()
   {
    	printf("save     - Sauve le fichier modifie\n");
    	printf("help     - Mode d'emploi\n");
    	printf("load     - Charge un fichier de fontes PXL\n");
    	printf("typ      - Affiche un caractere original PXL\n");
    	printf("typmod   - Affiche un caractere conserve\n");
    	printf("keep     - Conserve un ou plusieurs caracteres\n");
    	printf("edit     - Modifie un des caracteres conserves\n");
    	printf("typlong  - Affiche un 'longword' du fichier PXL\n");
    	printf("typword  - Affiche un 'word' du fichier PXL\n");
    	printf("compress - Comprime le buffer de modification\n");
    	printf("dmpdict  - Affiche le dictionnaire\n");
	printf("modif    - Modifie les parametres d'un caractere\n");
	printf("modfile  - Modifie les parametres du fichier\n");
    	printf("exit     - Sortie de l'editeur\n");
   }

