[net.sources] fontbanner source

marco@cselt.UUCP (Marco Mercinelli) (01/07/86)

/* fontbanner 21/3/1985 */

/*
 * fontbanner: print banners using UNIX fonts
 * 
 * fontbanner [-vh] [-12] [-f font] [-d dir] [strings] ...
 *
 * Author: Marco Mercinelli (CSELT - IS) mcvax!i2unix!cselt!marco
 */

#define COPYRIGHT  "fontbanner 1985 - by Marco Mercinelli, CSELT-IS (Italy)"

#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <ctype.h>
#include <vfont.h>

#ifdef VFONT_MAGIC
short	fontmagic = VFONT_MAGIC;
#else
short	fontmagic = 0436;
#endif

#define DEFAULTDIR   "/usr/lib/vfont"
#define DEFAULT_FONT "bocklin.14"

#define	WHITE	    ' '
#define	BLACK	    '#'
#define	BLACK2	    'O'
#define	HALFRIGHT   ')'
#define	HALFLEFT    '('
#define	NEXT	    '\n'

#define MAXUNPRINTABLE 10 /* Max number of unprintable char (> \177) allowed */

char *USAGE="usage:fontbanner [-vh] [-12] [-f font] [-d dir] [strings] ...\n";

char fontsdir[256];

struct header   FontHeader;
struct dispatch disptable[256] ;

int     fontfd      = -1;    /* File descriptor del file font                */
long	fbase;               /* Puntatore all'inizio delle bit map nel file  */
short 	vertical    = 0;     /* Indica banner verticale o orizzontale        */
short	nochange    = 1;     /* Indica se e' cambiato il font corrente       */
short	fontchanged = 0;     /* Indica se non e' stata data risposta a Font: */
char    style       = '1';   /* Stile di plottaggio ('1' o '2')              */
short	istty;		     /* Indica se stdout e' una tty		     */
char    fontname[80];	     /* Nome del font corrente                       */
short	error       = 0;     /* Indica un errore nel caricamento di un font  */
short	defaultfdir = 1;     /* Indica che la dir dei fonts e' DEFAULTFDIR   */
short	unprintable = 0;     /* Caratteri non stampabili (> \177) incontrati */
char	newline	    = '\n';
int     interactive_mode = 1; 

extern int errno;

char *gets(), *strcpy(), *strncpy(), *strcat(), *strncat(), *sprintf(),
     *malloc(), *realloc(),
     *listfonts();

long lseek();


main(argc,argv)

int    argc;
char **argv;

{
    fbase = sizeof(FontHeader)+sizeof(disptable);

    *fontname = *fontsdir = '\0';

    while ( --argc  && (**++argv == '-') ) /* tratta argomenti */
        getoptions(&argc, &argv);

    interactive_mode = !argc; /* =1 se non ci sono stringhe da stampare */
    istty = isatty(1);

    if ( defaultfdir )
        if ( accessdir(DEFAULTDIR) )
            (void)strncpy(fontsdir, DEFAULTDIR, sizeof(fontsdir));
        else {
            fprintf(stderr,
	            ".... Cannot open default fonts directory \"%s\"\n",
		    DEFAULTDIR);
            if ( !interactive_mode )
		exit(2);
            *fontsdir = '\0';
            defaultfdir = 0;
        }

    if ( interactive_mode )
        interactive();
    else
        not_interactive(argc, argv);

    if ( !istty )
        printf("\n\n%s\f\n", COPYRIGHT);

} /* main */

/*- NOT INTERACTIVE COMMAND HANDLER -------------- ------------------------*/

not_interactive(argc, argv)

int    argc;
char **argv;

{
    register char *c;

    if ( fontfd < 0 ){
        if ( defaultfdir ){ 
            /*
             * CARICA FONT DI DEFAULT
             */
            if ( (fontfd = load_font(DEFAULT_FONT)) < 0 ){
                fprintf(stderr,
		       ".... Cannot load default font \"%s\"\n", DEFAULT_FONT);
                exit(4);
            }
	} else {
	    fprintf(stderr, ".... No font specified\n");
	    goto bad;
	}
    }


    /*
     * TRATTA ARGOMENTI RIMANENTI
     */
    do {
        if ( error ) /* errore nel caricamento del font specificato */
            goto bad;

	if ( *(c = *argv) != '-' ) {
            /*
             * E' UNA STRINGA DA PLOTTARE
             */
            if ( *c == '\\' && ( c[1] == '-' || c[1] == '\\' ) )
                /*
                 * '\' elimina il significato di '-' o '\'
                 */
                c++;

            plot_string(c);

        } else 
    	    getoptions(&argc, &argv);

	argv++;

    } while ( --argc );

bad:
    fputs(USAGE, stderr);
    exit(7);

} /* not_interactive */

/*-- INTERACTIVE COMMAND HANDLER --------------------------------------------*/

interactive()

{
    register char *s;

    char  string[256];
    int   newfontfd;
    short notify = 1;


    if ( !*fontsdir )
        (void)strcpy(fontsdir, ".");

    fprintf(stderr, ".... Current fonts directory is \"%s\"\n", fontsdir);

    if ( defaultfdir && !error && fontfd < 0 ){
        /*
         * Se non ho specificato nessun font come argomento
         * cerca di caricare il font di default
         */
        if ( (fontfd = load_font(DEFAULT_FONT)) < 0 ) {
            fprintf(stderr, ".... Cannot load default font \"%s\"\n", DEFAULT_FONT);
            *fontname = '\0';
        } else {
            (void)strcpy(fontname, DEFAULT_FONT);
        }
    }

    for(;;){

        if ( fontfd < 0 ){
            fputs(".... Please choose a font file\n", stderr);
        } else do {

            /*
             * NOTIFICA IL FONT CORRENTE E IL MODO DI STAMPA
             * SE C'E' STATA UNA MODIFICA
             */

            if ( notify ){
                /* (void)fputc(newline, stderr); */
                fputs("\n[ Current font is ", stderr);
                if ( fontchanged )
                    fputs("now ", stderr);
                if ( nochange ){
                    fputs("still ", stderr);
		    nochange = 0;
		}
                fprintf(stderr, "\"%s\",", fontname);
                fprintf(stderr, " plot style %c ", style);
                if ( style == '1' )
                    fputs("(compact),", stderr);
                else
                    fputs("(accurate),", stderr);
                if ( vertical )
                    fputs(" vertical", stderr);
                else
                    fputs(" horizontal", stderr);
                (void)fputs(" ]\n", stderr);
                notify = 0;
            }
    
            /*
             * CHIEDE MESSAGGIO
             */
            fputs("Message : ", stderr);
            if ( (s = gets(string)) == NULL ){
                /*
                 * EOF: fine del lavoro
                 */
                (void)fputc(newline, stderr);
                return;
            }
            if ( *s )
                plot_string(s);
        } while ( *s );
    
        /*
         * CHIEDE FONT
         */

askfont:
        error = 0;

        /* (void)fputc(newline, stderr); */
        fputs("Font    : ", stderr);
        if ( (s = gets(string)) == NULL ){
            /*
             * EOF: fine del lavoro
             */
            (void)fputc(newline, stderr);
            return;
        }

        while ( isspace(*s) ) s++;
            
        /*
         * TRATTA LE OPZIONI
         */
        while ( *s == '-' ) {
            while ( *++s && !isspace(*s) ){ /* gruppo di opzioni */

                switch ( *s ){

                case 'v': /* VERTICAL */
                    if ( !vertical ){
                        vertical = 1;
                        notify = 1;
                    }
                break;

                case 'h': /* HORIZONTAL */
                    if ( vertical ){
                        vertical = 0;
                        notify = 1;
                    }
                break;

                case '1': /* PLOTTING STYLE 1/2 */
                case '2':
                    if ( style != *s ){
                        style = *s;
                        notify = 1;
                    }
                break;

                case 'f': /* -f default */
                break;

                case 'd': /* CHANGE FONTS DIRECTORY */
                    
                    /* elimina blanks */
                    for ( s++ ; *s && isspace(*s) ; s++ );

                    if ( !*s )
                        fputs(".... Missing fonts directory name\n", stderr);
                    else {

                        register char *d;
                        register int   i;
                        char pathbuf[100];

                        d = pathbuf;
                        i = 1;
                        while ( *s && !isspace(*s) && ++i < sizeof(fontsdir))
                            *d++ = *s++;
                        *d = '\0';
                        s--;
                        if ( !accessdir(pathbuf) ){
                            fprintf(stderr,
				    ".... Cannot access fonts directory %s \n",
				    pathbuf);
                            fprintf(stderr,
				    ".... Fonts directory is still \"%s\"\n",
				    fontsdir);
                        } else {
                            (void)strncpy(fontsdir, pathbuf, sizeof(fontsdir));
                            fprintf(stderr,
				".... Current fonts directory is now \"%s\"\n",
				fontsdir);
                        }
                    }

		    goto askfont;
                break;

                case 'l': /* LIST FONTS */
                    
                    /* elimina blanks fino al pattern */
                    for ( s++ ; *s && isspace(*s) ; s++ );

                    s = listfonts(s);

                    /* s deve puntare all'ultimo dei */
                    /* caratteri considerati         */
                    s--;

                    /* Si presuppone che se l'utente ha  */
                    /* chiesto la lista dei font voglia  */
                    /* cambiare il font corrente per cui */
                    /* viene ripetuta la richiesta del   */
                    /* nome di un font                   */

                    goto askfont;
                break;

                default:
                    fprintf(stderr, ".... Bad option \"%c\"\n", *s);
                    error = 1;
		    goto askfont;
                }
            }
            while ( *s && isspace(*s) ) s++;
        }

        newfontfd   = -1;
        fontchanged = 0;
        if ( *s && !error ){
            /*
             * E' stato specificato il nome di un nuovo font
             */
            while ( isspace(*s) ) s++;
            if ( strcmp(fontname, s) ){
                /* E' il nome di un nuovo font */
                if ( (newfontfd = load_font(s)) >= 0){
                    fontfd = newfontfd;
                    (void)strcpy(fontname, s);
                    fontchanged = 1;
                    notify = 1;
                } else {
		    /* errore nel caricamento del font. Ripete domanda */
                    error = 1;
		    goto askfont;
		}
            }
        } else {
	    if ( !notify ){
		/* non ci sono cambiamenti di nessun tipo segnala errore */
		/* per la notify                                         */
	        notify = 1;
		nochange = 1;
	    }
	}
    } /* for ever */

    /* NOT REACHED */

} /* interactive */


/*-- UTILITY ROUTINES -------------------------------------------------------*/

/*
 * GETOPTIONS tratta un insieme di opzioni in modo non interattivo
 *            esce appena trova un argomento che non e' una opzione
 */
getoptions(pargc, pargv)

int   *pargc;
char **pargv[];
{
    register int    argc;
    register char **argv;
    register char  *c;

    argc = *pargc;
    argv = *pargv;
    c    = *argv;

    /*
     * TRATTA OPZIONI
     */
    while ( *++c ){

        switch ( *c ){
    
        case 'v':
            vertical = 1;
        break;

        case 'h':
            vertical = 0;
        break;

        case '1':
        case '2':
            style = *c;
        break;

        case 'd': /* change default fonts directory */

            if ( ! --argc ){
                fputs(".... Missing fonts directory name\n", stderr);
		goto bad;
            }
            (void)strncpy(fontsdir, *++argv, sizeof(fontsdir));
            if ( !accessdir(fontsdir) ){
                fprintf(stderr,
		      ".... Cannot access fonts directory \"%s\"\n", fontsdir);
		goto bad;
            }
            defaultfdir = 0;
        break;

        case 'f':
            /*
             * carica un nuovo font
             */
            if ( ! --argc ){
                fputs(".... Missing font name\n", stderr);
		goto bad;
            }
            if ((fontfd = load_font(*++argv)) < 0){
                    error = 1; 
            } else {
                (void)strncpy(fontname, *argv, sizeof(fontsdir));
		fontchanged = 1;
	    }
        break;

        default:
            fprintf(stderr, ".... Bad option \"%c\"\n", *c);
	    goto bad;

        } /* switch */
    } /* while */

    *pargv = argv;
    *pargc = argc;

    return;

bad:
    fputs(USAGE, stderr);
    exit(4);
} /* getoptions */

/*
 * LISTFONTS esegue il comando:
 *           ls -F fontsdir/pattern >&2     se e' passato un pattern valido
 * altrimanti esegue
 *           ls -F -d fontsdir/* >&2
 * Ritorna il puntatore al primo carattere dopo il pattern
 */

char *
listfonts(paddr)

register char *paddr;
{
    register char *p;
    char  shcmd[100], buf[100];
    short slashs = 0; /* indica che il pattern contiene degli '/' */
    char  cbuf;

    fputs(".... List \"", stderr);

    p = paddr;
    if ( *p && !isspace(*p) ){ /* c'e' un pattern specificato */

	/* cerca fine pattern e gli mette temporaneamente \0 e */
	/* intanto controlla se il pattern contiene degli '/'  */
        for ( p; *p && !isspace(*p) ; p++){
            if ( *p == '/' )
	        slashs = 1;
	    if ( *p == '&' || !isprint(*p) ) /* puo' confondere lo shell */
               	*p = '?';
	}
	cbuf = *p;
	*p = '\0';

        /* controlla se il pattern contiene un path */
        /* se non lo contiene premette  cd fontsdir */

        if ( !slashs && *paddr != '.' ){
            /* il pattern non contiene un path     */
            /* esegue cd fontsdir;ls -F -d pattern */
            (void)sprintf(shcmd,"cd %s;ls -F -d %s", fontsdir, paddr);
	    (void)sprintf(buf, "%s/%s", fontsdir, paddr);
	    if ( accessdir(buf) )
		(void)strcat(shcmd, "/*");
            fprintf(stderr, "%s/", fontsdir);
        } else {
            /* il pattern contiene un path  */
            /* esegue ls -F -d pattern      */
            (void)sprintf(shcmd, "ls -F -d %s", paddr);
	    if ( accessdir(paddr) )
		(void)strcat(shcmd, "/*");
	    if ( *paddr != '.' && *paddr != '/' )
            	fputs("./", stderr);
        }

        (void)fputs(paddr, stderr);
	/* ripristina carattere di fine pattern */
	*p = cbuf;

    } else { /* non c'e' un pattern specificato */

        /* esegue cd fontsdir;ls -F */
        (void)sprintf(shcmd, "cd %s;ls -F", fontsdir);
        fprintf(stderr, fontsdir);
    }
    (void)strcat(shcmd, " >&2");
    (void)fputs("\"\n", stderr);

    if ( system(shcmd) )
        fputs( ".... Shell error\n", stderr);

    return(--p);

} /* listfonts */

/*
 * ACCESSDIR retorna 1 se il path si riferisce a una directory
 */
accessdir(path)

char *path;
{
	struct stat statbuf;

	if ( stat(path, &statbuf) < 0 )
		return(0);
	return( ((statbuf.st_mode & S_IFMT) == S_IFDIR) && 
		(statbuf.st_mode & S_IEXEC) );
}

/*-- PLOTTING ROUTINES ------------------------------------------------------*/

static short backslash;
static short controlchar;

plot_string(string)

char * string;
{
	register char *s;
	char  ch;

	backslash = 0;
	controlchar = 0;
	s = string;
	while ( (ch = *s++) != '\0' ){

		if ( ch < ' ' ){
			controlchar++;
			ch += '\100';
			plot_char(ch);
			continue;
		}

		if ( ch > '\177' ){
			fprintf(stderr,
				"unprintable char '\\%o' skipped\n", ch); 
			if ( ++unprintable > MAXUNPRINTABLE ){
				fputs(".... Too many unprintable chars\n", 
				      stderr);
				exit(1);
			}
			continue;
		}

		/* '\' toglie al carattere successivo l'eventuale */
		/* significato speciale ( \\ \^ )                 */

	   	if ( backslash ){
			backslash = 0;
			plot_char(ch);
			continue;
	   	}

		switch ( ch ){

		case '\\':
				if ( *s )
					backslash = 1;
				else
					plot_char('\\');
		break;

		/* se un carattere e' preceduto da '^' stampa i caratteri   */
		/* corrispondenti da '\000' a '\037' (da cntrl-@ a cntrl-_) */

		case '^':
			if ( controlchar || !*s || !(*s >= '@' && *s <= '_' ) )

			/* Se il carattere precedente era '^': control ^   */
			/* oppure sono a fine stringa                      */
			/* oppure il carattere successivo non e' compreso  */
			/* fra '@' e '_'  (non sarebbe un control...)      */

				plot_char('^');
			else
				controlchar = 1;
		break;

		default:
			plot_char(ch);

		}/*switch*/
	}/*while*/

	if ( !istty )
		/*
		 * se la stampa non e' su tty separa le stringhe con blank
		 */
		plot_char(' ');

} /* plot_string */




plot_char(c)

char c;
{

register struct dispatch *pdisp; /* Dispatch table del carattere              */
register int      len, col, bit;
	 int      ch;	         /* Carattere da plottare (ch = c)            */
static   int      prevch = -1;   /* Ricorda l'ultimo carattere plottato       */
static   char *charbits;         /* Buffer per la bitmap del carattere        */
static   unsigned buflen = 0;    /* Attuale dimensione del buffer             */
	 unsigned bmlen;	 /* Numero di byte componenti la bitmap       */
static	 int      H;	         /* Altezza della bitmap del carattere in bit */
static   int      W;	         /* Larghezza della bitmap carattere in bit   */
static   int      WB;	         /* Numero di byte in ogni riga della bit map */
static   int      HB;	         /* Indice dell'ultimo byte della prima col.  */
			         /* (primo byte dell'ultima linea)            */
	 char    *byteind;	 /* Punta al byte della bit map da plottare   */
register short    thisbyte;      /* Contiene il byte puntato da byteind       */
register short    thisbit;       /* Maschera per il bit corrente in thisbyte  */
	 int      vspace;        /* Spazio fra 2 caratteri in verticale       */



	ch = c;

	if ( controlchar )
		ch -= 0100;

	pdisp = &(disptable[ch]);

	if ( (ch != ' ') && ((bmlen = pdisp->nbytes) == 0) ){
	   	fputs("character  \"", stderr);
		if ( controlchar )
			(void)fputc('^', stderr);
		fprintf(stderr,"%c\" is not provided by font\n",c);
		if ( istty )
			goto out; 
		ch = ' ';
	}

   	if ( ch == ' ' ){
		/* 
		 * TRATTA CARATTERE BLANK
		 */
		if ( vertical ){
			/* Somma l'altezza del carattere '|' se */
			/* questo non e' previsto prova con il  */
			/* carattere 'a'. Se anche questo non   */
			/* e' previsto somma la massima altezza */

	      		if ( disptable['|'].nbytes )
		 		bmlen = disptable['|'].up;
			else {
	      			if ( disptable['a'].nbytes )
		 			bmlen = disptable['a'].up;
	      			else
		 			bmlen = FontHeader.maxx;
			}
		} else {
   			/* Se il carattere blank non e' previsto allora   */
			/* sommo solo la larghezza del carattere 'a' e se */
			/* anche questo non e' previsto prendo la massima */
			/* larghezza di un carattere                      */

			if ( pdisp->nbytes == 0 ){
	      			if ( disptable['a'].nbytes )
		 			bmlen = disptable['a'].width;
	      			else
		 			bmlen = FontHeader.maxx;
			}
			else
				bmlen = pdisp->width;
		}
		for ( col=0 ; col < bmlen ; col++ )
			plot_dot(NEXT);
	} else {
		/*
		 * TRATTA I CARATTERI STAMPABILI
		 */

		if ( prevch != ch || fontchanged ){

			/* se il carattere non e' uguale a quello precedente */
			/* (o non ho cambiato font)                          */

			/* LEGGE LA BITMAP DEL CARATTERE */

			if (lseek(fontfd,(long)(fbase+pdisp->addr),0)<(long)0){
				perror("lseek");
				exit(errno);
			}
			if ( buflen ){
				if ( bmlen > buflen ){
					/*
					 * l'attuale dimensione del buffer
					 * non e' sufficiente quindi questo
					 * viene espanso
					 */
					charbits = realloc(charbits, bmlen);
					if ( charbits == NULL){
						perror("realloc");
						exit(errno);
					}
					buflen = bmlen;
				}
			} else {
				/* non esiste ancora un buffer allocato */
				if ((charbits = malloc(buflen=bmlen)) == NULL){
					perror("malloc");
					exit(errno);
				}
			}
			if ( read(fontfd, charbits, (int)bmlen) != bmlen ){
				fputs(".... Error reading bit maps\n", stderr);
				perror("read");
				exit(2);
			}

			/* ALTEZZA DELLA BITMAP (in bit) */

			H = (pdisp->up) + (pdisp->down);

			/* LARGHEZZA DELLA BITMAP (in bit) */

			W = (pdisp->left) + (pdisp->right);

			/* NUMERO DI BYTES CHE FORMANO UNA RIGA DELLA BITMAP */

			WB = (W+7)>>3;

			/* INDICE DELL'ULTIMO BYTE DELLA PRIMA COLONNA */

			HB = (H-1)*WB;
		}

		/*
		 * PLOTTA CARATTERE
		 */

		thisbit  = 0x80;    /* primo bit in un byte     */

		if ( vertical ){

			/*
			 * CARATTERE PLOTTATO IN VERTICALE
			 */
			byteind = charbits; /* primo byte della bit map */
			thisbyte = *byteind & 0xff;

			for ( len=0 ; len < H ; len++ ){
				/* per tutte le linee */

				/* GLI SPAZI A SINISTRA DEL CARATTERE NON  */
				/* SONO COMPRESI NELLA BIT MAP SE left < 0 */

				for ( col=pdisp->left ; col < 0 ; col++ )
					plot_dot(WHITE);

				for ( bit = 0 ; bit < W  ; bit++ ){
					/* per tutti i bit di una linea */

					if ( thisbyte & thisbit )
						/* se il bit e' settato */
						plot_dot(BLACK);
					else
						plot_dot(WHITE);

					thisbit >>= 1; /* bit successivo */
					if ( !thisbit ){
						/*
						 * Passa al byte successivo
						 */
						thisbyte = *++byteind & 0xff;
						thisbit = 0x80;
					}
				}

				if ( thisbit != 0x80 ){
					/*
					 * L'ultimo byte della linea non era
					 * totalmente utilizzato:  forza il
					 * il passaggio al byte successivo 
					 */
					thisbyte = *++byteind & 0xff;
					thisbit = 0x80;
				}
					
				plot_dot(NEXT);
			}

			/*
			 * SE down < 0 GLI SPAZI SOTTO IL CARATTERE NON SONO
			 * COMPRESI NELLA BITMAP:  QUINDI DEVO AGGIUNGERLI ...
			 */

			/* OLD: lascia  troppo o troppo poco spazio !!!
			 *
			 * for ( len=pdisp->down ; len < 0 ; len++ )
			 *     plot_dot(NEXT);
			 */

			/* NEW:
			 * lascio sempre un ottavo di maxy (se down < 0)
			 * e comunque al minimo 1 carattere
			 */
			if ( pdisp->down < 0 ) {
				if ( fontchanged )
					/* ricalcola vspace */
			       		if ( (vspace=FontHeader.maxy>>3) == 0)
						vspace = 1;
				for ( len=0 ; len < vspace ;  len++ )
				    	plot_dot(NEXT);
			}
		} else {
			/*
			 * CARATTERE PLOTTATO IN ORIZZONTALE
			 */

			/* GLI SPAZI A SINISTRA DEL CARATTERE NON SONO */
			/* COMPRESI NELLA BIT MAP SE left < 0          */

			for ( col=pdisp->left ; col < 0 ; col++ )
				plot_dot(NEXT);

			byteind = &charbits[HB]; /* 1o byte ultima linea */

			for ( col=0 ; col < W ; col++ ){
				/* per tutte le colonne */

				/* GLI SPAZI SOTTO IL CARATTERE NON SONO */
				/* COMPRESI NELLA BIT MAP SE down < 0    */

				for ( bit=pdisp->down ; bit < 0 ; bit++ )
					plot_dot(WHITE);

				thisbyte = *byteind & 0xff;

				for ( bit = H-1 ; bit >= 0  ; bit-- ){
					/* per tutti i bit di una colonna */

					if ( thisbyte & thisbit )
						/* il bit e' settato */
						plot_dot(BLACK);
					else
						plot_dot(WHITE);

					byteind -= WB; /* linea precedente */
					thisbyte = *byteind & 0xff;
				}
				byteind += HB+WB; /* Torna a ultima linea    */
						  /* NB non cambia colonna   */

				thisbit >>= 1;    /* bit successivo nel byte */

				if ( !thisbit ){
					/*
					 * Passa al byte successivo stessa linea
					 * (ultimo byte colonna successiva)
					 */
					++byteind;
					thisbit = 0x80;
				}

				plot_dot(NEXT);
			}
			/* LASCIA LO SPAZIO FINO AL PROSSIMO CARATTERE */
			for( col=pdisp->width - W ; col > 0  ; col-- )
				plot_dot(NEXT);
		}
	}
out:
	prevch = ch;
	if ( controlchar )
		controlchar = 0;

} /* plot_char */




#define PSIZE	(float)1.66 /* rapporto fra altezza e larghezza di un */
			    /* carattere sulla stampante              */

plot_dot(newpoint)

char newpoint;

/* Prepara la linea di stampa in base al valore di newpoint:
 *
 * WHITE aggiunge spazi bianchi;
 * BLACK aggiunge un punto nero
 * NEXT  stampa la linea corrente e passa alla successiva
 *
 * Se si deve tracciare un segmento (bianco o nero) la sua lunghezza in
 * caratteri della stampante viene calcolata approssimando la dimensione
 * di ogni punto che la compone a 1.66 caratteri 
 */

{
	static char  line[256];		/* Buffer di stampa                */
	static char *firstfree;		/* Prima posizione libera in line  */
	static char  previous  = NEXT;  /* Carattere precedente            */
	static int   pointnum;		/* Lunghezza del segmento in punti */
	static float reminder = 0.0;	/* resto dell'arrotondamento prec. */

	int 		numchar;        /* lunghezza segmento in caratteri */
	double 		vnumchar;       /* lunghezza virtuale segmento     */
	short		halfleft  = 0;
	short		halfright = 0;
	char		newchar;

	/* Se il carattere attuale e' diverso dal precedente vuol */
	/* dire che e' cambiato il tipo di segmento: calcolo la   */
	/* lunghezza del segmento in caratteri della stampante e  */
	/* riempio opportunamente line.                           */
	/* Se il carattere attuale e' uguale al precedente        */
	/* incremento il conto della lunghezza del segmento       */
	/* Se lo stile e' il secondo: usa BLACK2 invece di BLACK  */
	/* se la lunghezza del segmento e' compresa fra 0.33333 e */
	/* 0.66666 viene stampato un carattere intermedio che e'  */
	/* HALFLEFT se inizia un segmento BLACK e HALFLEFT se lo  */
	/* termina.                                               */

	if ( newpoint == previous ){
		/*
		 * PERMANENZA
		 */
		if ( newpoint == NEXT ) { /* LINEA VUOTA */
			if ( write(1, &newline, 1) < 0 ){
				perror("write");
				exit(errno);
			}
		} else
			pointnum++; /* incrementa la lunghezza del segmento */
	} else { 
		/*
		 * VARIAZIONE
		 */
		if ( previous == NEXT ){
			/*
			 * INIZIO LINEA NON VUOTA O PRIMISSIMA ESECUZIONE
			 */
			firstfree = line;
			pointnum = 1;
			reminder = 0.0;
		} else {
			/*
			 * inserisco segmento precedente in line
			 */

			register int 	i;
			register char  *f; /* firstfree */

			f = firstfree;

			vnumchar = PSIZE*pointnum + reminder;
			numchar  = vnumchar;
			reminder = vnumchar - numchar;

			if ( style == '2' ){
				if ( reminder >= 0.66666 ){
					/*
					 * approssima per eccesso
					 */
					numchar++;
					reminder -= 1.0;
				} else {
					if ( reminder >= 0.33333 ){
						/*
						 * approssimazione intermedia
						 */
						if ( previous == BLACK )
							halfright++;
						else
							if ( newpoint == BLACK )
								halfleft++;
						reminder -= 1.0;
					}
				} /* altrimenti approssima per eccesso */

				if ( previous == BLACK )
					newchar = BLACK2;
				else
					newchar = previous;

				for ( i=0 ; i < numchar ; i++ )
					*f++ = newchar;

				if ( halfright ){
					*f++ = HALFRIGHT;
				} else
					if ( halfleft ){
						*f++ = HALFLEFT;
					}

			} else { /* style 1 */
				if ( reminder >= 0.5 ){
					/*
					 * approssima per eccesso
					 */
					numchar++;
					reminder -= 1.0;
				}
				for ( i=0 ; i < numchar ; i++ )
					*f++ = previous;
			}
					
			if ( newpoint == NEXT ){ /* FINE LINEA */
				/*
				 * STAMPA LINEA
				 */

				*f++ = newline;
				*f = '\0';
				if ( write(1, line, strlen(line)) < 0 ){
					perror("write");
					exit(errno);
				}
				pointnum = 0;
			} else {
				/*
				 * TRANSIZIONE DA WHITE A BLACK O VICEVERSA
				 */
				pointnum = 1;
			}
			firstfree = f;
		}
		previous = newpoint;
	}
} /* plot_dot */


/*-- LOAD FONT ROUTINES -----------------------------------------------*/

load_font(fontfile)

char *fontfile;

/* This routine reads in the appropriate font file */


{
    register char *pf;
    char           fontpath[100];
    int            f;
    short	   doinvert=0;


    fontpath[0] = '\0';

    /* vede se il nome del font contiene gia' un pathname */
    pf = fontfile;
    while(*pf && *pf != '/' ) pf++;

    if ( *pf != '/' ){ /* aggiungo il path */
    	(void)strcpy(fontpath, fontsdir);
	(void)strcat(fontpath, "/");
    }

    (void)strcat(fontpath,fontfile);

    if((f = open(fontpath,0)) < 0 ){
	fprintf(stderr,".... Cannot open font file \"%s\"\n",fontpath);
	return(-1);
    }

    /* Get the FontHeader and check magic number */

    if(read(f,(char *)&FontHeader,sizeof(FontHeader)) != sizeof(FontHeader)){
	fprintf(stderr,".... Bad FontHeader in font file %s\n",fontpath);
	return(-1);
    }

    if(FontHeader.magic != fontmagic){
	/*
	 * L'header e' formato da short che su vax sono di 2 byte.
	 * Su alcuni processori (es. sun) i byte in uno short sono invertiti.
	 * Prova quindi a invertire prima di dichiarare bad magic
	 */
	
    	invert((u_short *)&FontHeader.magic);

    	if(FontHeader.magic != fontmagic){
	    fprintf(stderr,".... Bad magic number in font file %s\n", fontpath);
	    return(-1);
	} else {
    	    invert(&FontHeader.size);
	    invert((u_short *)&FontHeader.maxx);
	    invert((u_short *)&FontHeader.maxy);
	    invert((u_short *)&FontHeader.xtend);
	    doinvert = 1;
	}
    }

    /* Get disptablees */
    if(read(f,(char *)disptable,sizeof(disptable)) != sizeof(disptable)){
	fprintf(stderr,".... Bad disptable array in font file %s\n",fontpath);
	return(-1);
    }

    if ( doinvert ) {
        register int i;
	register struct dispatch *pd;

	pd = disptable;
 
        for ( i = 0 ; i<256 ; i++ ){
            invert((u_short *)&(pd->nbytes));
            invert((u_short *)&(pd->addr));
            invert((u_short *)&(pd->width));
            pd++;
        }
    }
    return(f);
} /* load_font */

/*
 * Inverte i due byte in uno short (16 bit)
 */
invert(s)

u_short *s;
{
        char tmp;
        register char *c1,*c2;

        c1 = c2 = (char *)s;
        c2++;
        tmp = *c1;
        *c1 = *c2;
        *c2 = tmp;
}