home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 3: Developer Tools / Linux Cubed Series 3 - Developer Tools.iso / utils / console / svgatext.3 / svgatext / SVGATextMode-1.3 / contrib / loadfont / loadfont.c next >
Encoding:
C/C++ Source or Header  |  1995-04-13  |  14.1 KB  |  494 lines

  1. /*
  2.  * loadfont.c (maybe), a Linux console font loader by Albert Cahalan
  3.  * albert@ccs.neu.edu (also adc@coe.neu.edu & acahalan@lynx.neu.edu)
  4.  * Based on setfont.c by Eugene Crosser & aeb.
  5.  *
  6.  * Version 0.1
  7.  *
  8.  * This file will be part of the fe font editor package.
  9.  * Copyright 1995 Albert Cahalan; all rights reserved.
  10.  *
  11.  * This program is free software; you can redistribute it and/or
  12.  * modify it under the terms of the GNU General Public License
  13.  * as published by the Free Software Foundation; either version
  14.  * 2 of the License, or (at your option) any later version.
  15.  *
  16.  */
  17.  
  18. /*
  19.  * This program should read these fonts:
  20.  * Raw files with no header
  21.  * .psf files with 4-byte header
  22.  * .cpi multifont files, like those included with DOS
  23.  * .cp files with 1 font in several sizes
  24.  * *** Font must be 8x6 - 8x32 with 256 chars ***
  25.  */
  26.  
  27. /*
  28.  * Help!
  29.  * How do I convert "Code Page 161", "Latin 1", "France", and "ISO 03" ?
  30.  */
  31.  
  32. #include <stdio.h>
  33. #include <memory.h>
  34. #include <fcntl.h>
  35. #include <stdlib.h>
  36. #include <unistd.h>
  37. #include <sys/types.h>
  38. #include <sys/stat.h>
  39. #include <sys/ioctl.h>
  40. #include <sys/kd.h>
  41.  
  42. #ifndef TRUE
  43. #define TRUE (1)
  44. #define FALSE (0)
  45. #endif
  46.  
  47. #ifndef bool
  48. #define bool int
  49. #endif
  50.  
  51. typedef struct _font {
  52.   char data[8192];     /* font data with characters aligned to 32 bytes */
  53.   char name[1024];     /* full pathname to font file */
  54.   int offset;          /* where in the file, -1 if size changed */
  55.   int unit;            /* how tall */
  56.   bool was_modified;   /* for the editor */
  57.   bool readonly;       /* for the editor */
  58.   short codepage;      /* what int'l codepage */
  59. } FONT;
  60.  
  61. char *progname;
  62.  
  63. int error;    /* there was an error */
  64. int dbl;      /* true if font gets doubled */
  65. int viewonly; /* true if only seeking info */
  66. int dumping;  /* true if dumping to disk */
  67. int cp;       /* requested code page */
  68. char *ifil;   /* name of input file */
  69. char *ofil;   /* name of output file */
  70. FILE *fp;     /* input file */
  71. int iunit;    /* requested character height */
  72.  
  73.  
  74. extern int opterr, optind;
  75. extern char *optarg;
  76.  
  77. int  dumpfont(FONT *fnt);
  78. int  filesize(int fd);
  79. bool findfile(char name[], char *reqname);
  80. int  guessunits(char *buf);
  81. void init(void);
  82. bool openfont(char *name, char *reqname);
  83. void readfont(FONT *fnt);
  84. int  savefont(FONT *fnt);
  85. int  search_cp(void);
  86. int  seekfont(int iunit);
  87. int  uploadfont(char *readytogo);
  88. void usage(char *msg);
  89.  
  90. /*****************************************************/
  91. int main(int argc, char **argv){
  92.   FONT *stdfont;
  93.   int i;
  94.  
  95.   progname = argv[0];
  96.   init();
  97.   while ((i = getopt(argc, argv, "c:s:dv2")) != -1){
  98.     switch(i){
  99.       case 'c':
  100.         if(cp==0) cp = atoi(optarg);
  101.         else usage("Make up your mind, what code page?");
  102.         if(cp==0) usage("Code page 0 causes internal errors!");
  103.     break;
  104.       case 's':
  105.         if(iunit==0) iunit = atoi(optarg);
  106.         else usage("Make up your mind, what size?");
  107.         if(iunit < 6 || iunit > 32) usage("Insane font size!");
  108.     break;
  109.       case 'd':
  110.         if(!dumping) dumping = TRUE;
  111.         else usage("Can't take a dump twice.");
  112.     break;
  113.       case 'p':
  114.         if(!dumping) dumping = 2;  /* .psf dump */
  115.         else usage("Can't take a dump twice.");
  116.     break;
  117.       case '2':
  118.         if(!dbl) dbl = TRUE;
  119.         else usage("Already doubled. Already doubled.");
  120.     break;
  121.       case 'v':
  122.         if(!viewonly) viewonly = TRUE;
  123.         else usage("Already in viewonly mode.");
  124.     break;
  125.       case '?': usage("Bad option, you need help.");
  126.       default: usage("Internal error:  getopt returned unknown token.");
  127.     }
  128.   }
  129.  
  130.   /* Check parameters for sanity */
  131.   if(dbl && (iunit>16)) fprintf(stderr,"Font too big, was truncuated.\n");
  132.   if(optind==argc){ /* no file */
  133.     if(dumping) usage("Dump font where?");
  134.     else ifil="";
  135.   }
  136.   if(optind+1==argc){ /* one file */
  137.     if(dumping) ofil=argv[optind];
  138.     else ifil=argv[optind];
  139.   }
  140.   if(optind+2==argc){ /* two files */
  141.     if(dumping){ /* dump then load */
  142.       usage("Dump what?");
  143.     }else{ /* load then dump w/o ioctl (convert) */
  144.       ifil=argv[optind];
  145.       ofil=argv[optind+1];
  146.     }
  147.   }
  148.   if(optind+2<argc){ /* too many files */
  149.     usage("Way too many parameters...");
  150.   }
  151.   if(!ifil && !ofil) usage("Oh, fuck!"); /* This should never happen... */
  152.  
  153.   if (ofil && dumping){
  154.     stdfont = calloc(1,sizeof(FONT));
  155.     stdfont->unit=iunit;
  156.     strncpy(stdfont->name,ofil,1023);
  157.     if(dumpfont(stdfont)==0) savefont(stdfont);
  158.     free(stdfont);
  159.     ofil=0;
  160.   }
  161.  
  162.   if(ifil) {        /* Get a font from disk. */
  163.     stdfont = calloc(1,sizeof(FONT));
  164.     if(!openfont(stdfont->name,ifil)) return 1;
  165.     stdfont->unit = seekfont(iunit);
  166.     if(!viewonly) fprintf(stderr, "Units are %u.\n",(unsigned char)(stdfont->unit));
  167.     if((stdfont->unit>5) && (stdfont->unit<33)){
  168.       if(!viewonly) readfont(stdfont);
  169.       fclose(fp);
  170.       if(ofil && !viewonly){ /* conversion only */
  171.         strncpy(stdfont->name,ofil,1023);
  172.         savefont(stdfont);
  173.       }else{ /* send font to kernal */
  174.         uploadfont(stdfont->data);
  175.       }
  176.     }else if(!viewonly) {
  177.       fclose(fp);
  178.       fprintf(stderr,"Bad font size %i\n",stdfont->unit);
  179.       return(1);
  180.     }
  181.     free(stdfont);
  182.   }
  183.  
  184.   return(0);
  185. }
  186. /*****************************************************/
  187. void init(void){
  188.   ifil = 0;
  189.   ofil = 0;
  190.   iunit = 0;
  191.   error = FALSE;
  192.   dbl = FALSE;
  193.   dumping = FALSE;
  194.   viewonly = FALSE;
  195.   cp = 0;
  196.   fp = (FILE *)0xdeadbeef; /* cause an error if file not opened */
  197. }
  198. /*****************************************************/
  199. /*********************************************/
  200. int dumpfont(FONT *fnt) {
  201.   int fd;
  202.   /* we do not want to read, but only need fd */
  203.   if ((fd=open("/dev/console",0)) < 0) fd=0;
  204.   if(ioctl(fd,GIO_FONT,fnt->data)) {
  205.     perror("GIO_FONT ioctl error");
  206.     close(fd);
  207.     return(1);
  208.   }
  209.   close(fd);
  210.   if (fnt->unit == 0) fnt->unit=guessunits(fnt->data);
  211.   if (fnt->unit < 6){
  212.     fprintf(stderr, "Found nothing big enough to save.\n");
  213.     return(1);
  214.   }
  215.   return(0);
  216. }
  217. /*********************************************/
  218. int savefont(FONT *fnt) {
  219.     int i;  
  220.         if((fp = fopen(fnt->name, "r+")) == NULL){   /* read,write */
  221.           if((fp = fopen(fnt->name, "w")) == NULL){  /* create the file */
  222.         perror(fnt->name);
  223.         return(-1);
  224.       }
  225.     } else {
  226.       if(seekfont(fnt->unit) != fnt->unit){
  227.         fprintf(stderr, "Wrong font size.\n");
  228.             fclose(fp);
  229.         return(-1);
  230.       }
  231.     }
  232.     for (i = 0; i < 256; i++)
  233.       if (fwrite(fnt->data+(32*i), (unsigned int)fnt->unit, 1, fp) != 1) {
  234.       perror("Cannot write font file");
  235.       return(-1);
  236.         }
  237.     printf("Saved 8x%d font in %s\n", fnt->unit, fnt->name);
  238.     fclose(fp);
  239.     return 0;
  240. }
  241. /*********************************************/
  242. int guessunits(char *buf){ /* save font as efficiently as possible */
  243.   int i;
  244.   int unit;
  245.   for (unit = 32; unit > 0; unit--)
  246.     for (i = 0; i < 256; i++)
  247.       if (buf[32*i+unit-1]) return unit;
  248.   return 0; /* keep compiler happy */
  249. }
  250. /*********************************************/
  251. void readfont(FONT *fnt){
  252.   int i;
  253.   if(dbl){
  254.     for (i=0; i<256; i++)
  255.       if (fread(fnt->data+(16*i), (unsigned int)fnt->unit, 1, fp) != 1) { /* Note the 16 */
  256.         perror ("Cannot read font from file");
  257.     exit (1);
  258.       }
  259.     for (i=4095; i>=0; i--){ /* Time to double the font */
  260.       *(fnt->data+(i*2))   = *(fnt->data+i);
  261.       *(fnt->data+(i*2+1)) = *(fnt->data+i);
  262.     }
  263.     fnt->unit=fnt->unit*2; /* store real size in FONT struct */
  264.     if(fnt->unit>32){
  265.       fprintf(stderr,"Font too big, was truncuated.\n");
  266.       fnt->unit=32;
  267.     }
  268.     fnt->was_modified=TRUE; /* we can't put this back where it came from */
  269.   }else{
  270.     for (i=0; i<256; i++)
  271.       if (fread(fnt->data+(32*i), (unsigned int)fnt->unit, 1, fp) != 1) { /* Note the 32 */
  272.         perror ("Cannot read font from file");
  273.     exit (1);
  274.       }
  275.   }
  276. }
  277. /*********************************************/
  278. void usage(char *msg){
  279.   fprintf(stderr, "Error:  %s\n", msg);
  280.   fprintf(stderr, "\
  281. Usage:  %s [-d] [-2] [-v] [-c codepage] [-s fontsize] font1 [font2]
  282. If no -d is given, and no font, then the font \"default\" is loaded.
  283. With two fonts a conversion is done.
  284. Options:
  285.  -v        View info only.
  286.  -2        Double the height as a font is read in.
  287.  -d        Dump current font to a file.
  288.  -c codepage    Select a codepage from a multi-font file.
  289.  -s fontsize    Select a font size from a multi-font file.
  290. ", progname);
  291.   exit(1);
  292. }
  293. /*********************************************/
  294. int seekfont(int iunit){
  295.     int hdr;
  296.     int size;
  297.  
  298.     size=filesize(fp->_fileno);
  299.     if(size==0){
  300.       return(0);  /* nothing there, may be valid if writing */
  301.     }
  302.     
  303.     if (size == 9780) {  /* This is a codepage file */
  304.     /* normal code page: first 34 bytes main header,
  305.        then 8x16, 8x14, and 8x8 fonts each preceded by 6 byte subheader */
  306.     return(search_cp());
  307.     }
  308.  
  309.     if((size>9780) && (size<65537)){  /* This is a big file, might be .cpi */
  310.         int cpnum;
  311.         char cpihdr[25];
  312.         char cpimagic[] = "\377FONT   ";
  313.     if (fread(cpihdr, 25, 1, fp) != 1) {
  314.         perror("Error reading input font .cpi header");
  315.         return(-1);
  316.     }
  317.     if(strncmp(cpimagic,cpihdr,8) != 0){ /* What the hell? */
  318.       fprintf(stderr, "Unknown font file type.\n");
  319.       return(-1);
  320.     }
  321.     cpnum=cpihdr[23]; /* number of .cp files inside .cpi */
  322.     fprintf(stderr, "%i code pages in this .cpi file.\n",cpnum);
  323.     /* start a loop here checking each .cp part for a cp/unit match */
  324.     while(cpnum){
  325.       int tmpunits;
  326.       tmpunits=search_cp();
  327.       if(tmpunits && !viewonly) return(tmpunits);
  328.       cpnum--;
  329.     }
  330.     if(!viewonly){
  331.       fprintf(stderr, ".cpi file did not contain requested font.\n");
  332.       return(-1);
  333.     }
  334.     return(0);
  335.     }
  336.     
  337.     /* Not a normal codepage file, so do basic error checking & setup. */
  338.     if (iunit) {
  339.         fprintf(stderr, "This file contains only 1 font.\n");
  340.         return(-1);
  341.     }
  342.     hdr = (size & 255);
  343.     iunit = (size >>8);
  344.     if (iunit < 6 || iunit > 32) {
  345.         /* Although font sizes less than 6 are valid, they are stupid. */
  346.     fprintf(stderr, "Bad input file size.\n");
  347.     return(-1);
  348.     }
  349.  
  350.     if (hdr == 4) {                       /* .psf file */
  351.     char psfhdr[4];
  352.     if (fread(psfhdr, 4, 1, fp) != 1) {
  353.         perror("Error reading header input font");
  354.         return(-1);
  355.     }
  356.     /* note: this depends on endianness */
  357.     if (psfhdr[1] != 0x04 || psfhdr[0] != 0x36) {
  358.         fprintf(stderr, "Unrecognized font format\n");
  359.         return(-1);
  360.     }
  361.     if (psfhdr[2] != 0) {
  362.         fprintf(stderr, "Unsupported psf file mode\n");
  363.         return(-1);
  364.     }
  365.     if(size != hdr + 256*psfhdr[3]) {
  366.         fprintf(stderr, "Input file: bad length\n");
  367.         return(-1);
  368.     }
  369.     return(iunit);
  370.     }
  371.     
  372.     if (hdr == 0) return(iunit);  /* must be raw file, needs no work */
  373.     
  374.     if (hdr == 40) {                       /* .cp file with only one font */
  375.     return(search_cp());
  376.     }
  377.     
  378.     /* add more file types here */
  379.     fprintf(stderr, "Unknown input file type.\n");
  380.     return(-1);
  381. }
  382. /*********************************************/
  383. int search_cp(void){ /* return num scanlines, discard cp number? */
  384.   char hdr[34];
  385.   unsigned short numfonts;
  386.   unsigned short fontsleft;
  387.   unsigned short thispage;
  388.   bool skip;
  389.   unsigned short *sptr;
  390.   sptr=(short *)hdr;
  391.   if(fread(hdr, 34, 1, fp) != 1) {
  392.     perror("Error reading .cp header");
  393.     return(0);
  394.   }
  395.   numfonts=sptr[15];
  396.   skip=FALSE;
  397.   thispage=sptr[8];
  398.   if(viewonly){
  399.     fprintf(stderr,"Code page %u with %u fonts.\n",thispage,numfonts);
  400.   }else{
  401.     if( (cp!=0) && (cp!=thispage) ){
  402.       skip=TRUE;/* seek to next cp */
  403.     }else{
  404.       fprintf(stderr,"Code page %u found.\n",thispage);
  405.     }
  406.   }
  407.   fontsleft=numfonts;
  408.   while(fontsleft--){
  409.     if(fread(hdr, 6, 1, fp) != 1) {
  410.       perror("Error reading .cp subheader");
  411.       return(0);
  412.     }
  413.     if(viewonly) fprintf(stderr,"%ux%u ",hdr[1],hdr[0]);
  414.     if((hdr[1]==8)&&(!viewonly)&&(!skip)){
  415.       if((iunit==0)&&(numfonts==1)) return(hdr[0]); /* didn't care, this will do */
  416.       if(hdr[0]==iunit) return(iunit);
  417.     }
  418.     fseek(fp,256*hdr[0],SEEK_CUR);/* seek to end of font */
  419.   }
  420.   if((cp==thispage)&&(!viewonly)) fprintf(stderr,"Multiple sizes, which one?");
  421.   fprintf(stderr,"\n");
  422.   return(0);
  423. }
  424. /*****************************************************/
  425. /* find input file; leave name in pathname[] */
  426. bool findfile(char name[], char *reqname) {
  427.   char *dirpath[] = { "", "/usr/lib/kbd/consolefonts/", 0 };
  428.   char *suffixes[] = { "", ".psf", ".cp", ".cpi", ".fnt", 0 }; /* fot fon ttf */
  429.   char **dp, **sp;
  430.  
  431.   for (dp = dirpath; *dp; dp++) {
  432.     if (*reqname == '/' && **dp) continue;
  433.     for (sp = suffixes; *sp; sp++) {
  434.       if (strlen(*dp)+strlen(reqname)+strlen(*sp)+1 > 1024) continue;
  435.       /* name will not be bigger than allowed, 1024 chars */
  436.       sprintf(name, "%s%s%s", *dp, reqname, *sp);
  437.       if((fp=fopen(name, "r")) != NULL) return TRUE;
  438.     }
  439.   }
  440.   return FALSE;
  441. }
  442. /*********************************************/
  443. /*********************************************/
  444. bool openfont(char *name, char *reqname){
  445.     char defname[20];
  446.     if (*reqname) {  /* a specific file was requested */
  447.     if (!findfile(name, reqname)) {
  448.         fprintf(stderr, "Cannot open font file %s.\n", reqname);
  449.         return FALSE;
  450.     } else return TRUE;
  451.     } else {   /* try to find some default file */
  452.         sprintf(defname, "%i", cp);
  453.     if (findfile(name,defname)) return TRUE;
  454.         sprintf(defname, "default8x%i", iunit);
  455.     if (findfile(name,defname)) return TRUE;
  456.         sprintf(defname, "8x%i", iunit);
  457.     if (findfile(name,defname)) return TRUE;
  458.     
  459.     if (findfile(name,"default")) return TRUE;
  460.     if (findfile(name,"8x8plus")) return TRUE;
  461.         fprintf(stderr, "Cannot find default font.\n");
  462.     return FALSE;
  463.     }
  464. }
  465. /*********************************************/
  466. int filesize(int fd){
  467.   /* pass a file descriptor (maybe fp->_fileno, fp is FILE*), get the size. */
  468.   struct stat stbuf;
  469.   if (fstat(fd, &stbuf)) {
  470.     perror("Couldn't stat file");
  471.     exit(1);
  472.   }
  473.   return(stbuf.st_size);
  474. }
  475.  
  476. /*********************************************/
  477. int uploadfont(char *readytogo){ /* give font to kernal for display */
  478.     int fd;
  479.     if(viewonly){
  480.       fprintf(stderr,"Pretended to upload font to kernal.\n");
  481.       return(0);
  482.     }
  483.     /* we do not want to read, but only need fd */
  484.     if ((fd=open("/dev/console",0)) < 0) fd=0;
  485.     if(ioctl(fd,PIO_FONT,readytogo)) {
  486.       perror("PIO_FONT ioctl error");
  487.       close(fd);
  488.       return(1);
  489.     } else fprintf(stderr, "Uploaded font to kernal.\n");
  490.     close(fd);
  491.     return(0);
  492. }
  493. /*********************************************/
  494.