    1.0 An Overview of the Photon Font (PHF) File
        -----------------------------------------

        The Photon Font File (which we will refer to as a PHF from this point on),
        is generated from universally available .bdf files.  The utility used to
        create the PHF is called bdf_2_phf, and ships standard with Photon.

        There are four distinct components to a PHF.  They are as follows:

            1.  The header component
            2.  The bitmap component.
            3.  The metric component
            4.  The index component

        The PHF format is also structured in the order listed above.  A visual
        representation is below:

                ---------------------------------  Offset 0
                |                               |
                |       Header Component        |
                |                               |
                ---------------------------------
                |                               |
                |       Bitmap Component        |
                |                               |
                ---------------------------------
                |                               |
                |       Metric Component        |
                |                               |
                ---------------------------------
                |                               |
                |       Index Component         |
                |                               |
                ---------------------------------  Offset N

        Each component, with respect to character order, runs from the smallest Unicode
        value to the largest.  For example, if the PHF contains the Unicode range 0x0020 0x00FF,
        the first element in the Bitmap, Metric, and Index component will correspond to 0x0020,
        and the second element in each component to 0x0021, and so on.

    1.1 THE HEADER COMPONENT
        --------------------

        The header structure contains information relevant to
        the entire font, and is defined as follows:

            typedef struct
            {   short               Status;         /* For a file, MUST be set to 'QW' */
                unsigned short      Flags;
                _PointStruct        Size;
                _PointStruct        Extent;
                unsigned short      Spare1;
                unsigned short      ImageOffset;
                unsigned short      BPChar;
                unsigned short      WidthTabOffset;
                unsigned short      Spare2[4];
                short               UnderLinePos;
                short               BaseLinePos;
                unsigned short      AsciiOffset;
                unsigned short      AsciiLength;
                char                Description;
            } _FontStruct;

        A _PointStruct is defined as follows:

            typedef struct
            {   short               x, y;
            } _PointStruct;

    1.2 THE INDEX COMPONENT
        -------------------

        Bitmaps for each glyph can be of varying sizes.
        An offset into the PHF is required in order to
        locate the desired bitmap.  The _FONT_IndexPerChar
        bit will be high in all currently published PHFs.

        if(Header.Flags & _FONT_IndexPerChar)
        {  Header.AsciiLength * sizeof(short);
        }

        Flags are as follows:

            #define _FONT_IndexPerChar      0x0100

    1.3 THE METRIC COMPONENT
        --------------------

        Depending on the type of PHF (there are currently two), the metric
        component will be different.  The definitions are below.

            if(Header.Flags & _FONT_WidthPerChar)
            {  Header.AsciiLength * sizeof(short)
            }
            else if(Heaader.Flags & _FONT_MetricPerChar)
                 {  Header.AsciiLength * sizeof(_FontMetricStruct)
                 }
                 else
                   return(FALSE);

        A _FontMetricStruct is defined as:

            typedef struct
            {   _PointStruct        Size;           /* Bytes per line == (Size.x+7)>>3  */
                signed char         BaseLinePos;
                signed char         LeftBearing;
                short               Width;
            } _FontMetricStruct;

        Flags are as follows:

            #define _FONT_WidthPerChar      0x0200
            #define _FONT_MetricPerChar     0x0400  /* Metrics and Width are exclusive */

    1.4 THE BITMAP COMPONENT
        --------------------

        This component consists of a byte array.  Each glyph bitmap
        is access by seeking to the offset specified in the Index
        Component, then reading/writing the bitmap.

    1.5 EXAMPLE
        -------

    What follows is a simple terminal based program that allows text based
    editing of a PHF.  Also appended, are necessary header files.

    /* edit.c */

    #include
    #include
    #include
    #include
    #include
    #include
    #include "__g_fontfile.h"

    #define INDENT 2

    _FontStruct         hdr;
    short               * width = NULL, * ix = NULL;
    _FontMetricStruct   * metric = NULL;
    char                bitmap[1024];
    int                 fd = -1, posx = 0, posy = 0, szx = 0, szy = 0, bitmaplen = 0, bitmapbpl = 0;

    int FindDef(int from, int dir)
    {   int i = 0;

        if(dir == 1)
        {   for (i = (from != -1) ? from + 1 : 0; i < hdr.AsciiLength; ++i)
              if(hdr.Flags & _FONT_WidthPerChar && width[i] != 0)
                return(i);
              else if(hdr.Flags & _FONT_MetricPerChar && metric[i].Width != 0)
                     return(i);
                   else
                     return(i);

            return(from);
        }
        else if (dir == -1)
             {  for(i = (from != -1) ? from - 1 : hdr.AsciiLength - 1; i >= 0; --i)
                  if(hdr.Flags & _FONT_WidthPerChar && width[i] != 0)
                    return(i);
                  else if(hdr.Flags & _FONT_MetricPerChar && metric[i].Width != 0)
                         return(i);
                       else
                         return(i);

                return(from);
             }

        return(-1);
    }

    void DrawImage(int ch)
    {   int i = 0, x = 0, y = 0;

        if(hdr.Flags & _FONT_WidthPerChar)
        {  szx = width[ch], szy = hdr.Size.y;
        }
        else if(hdr.Flags & _FONT_MetricPerChar)
             {  szx = metric[ch].Size.x, szy = metric[ch].Size.y;
             }
             else
             {  /* should never happen at this point */
             }

        lseek(fd, ix[ch], SEEK_SET);
        read(fd, bitmap, bitmaplen = (bitmapbpl = ((szx + 7) >> 3)) * szy);
        term_clear(TERM_CLS_SCR);
        term_printf(0, 0, TERM_HILIGHT, "U+%04X", hdr.AsciiOffset + ch);

        for(y = 0; y < szy; ++y)
          for(x = 0; x < bitmapbpl; ++x)
            for(i = 0; i < 8; ++i)
              term_printf(INDENT + y, INDENT + x * 8 + i, TERM_NORMAL, (bitmap[y * bitmapbpl + x] & (0x80 >> i)) ? "*" : " ");

        term_printf(INDENT + szy + 1, 0, TERM_HILIGHT, "BROWSE?");
        term_clear(TERM_CLS_EOL);
        term_flush();
    }

    void SaveImage(int ch)
    {   lseek(fd, ix[ch], SEEK_SET);
        write(fd, bitmap, bitmaplen);
    }

    void main(int argc, char *argv[])
    {   int ch = 0, bit = 0, quit = 0, edit = 0, dirty = 0;
        unsigned char byte;

        if((fd = open(argv[1], O_RDWR)) == -1)
          return;

        read(fd, &hdr, sizeof(_FontStruct));

        if(hdr.Flags & _FONT_IndexPerChar)
        {  if((ix = malloc(hdr.AsciiLength * sizeof(short))) == NULL)
             return;

           lseek(fd, hdr.ImageOffset, SEEK_SET);
           read(fd, ix, hdr.AsciiLength * sizeof(short));
        }

        if(hdr.Flags & _FONT_WidthPerChar)
        {  if((width = malloc(hdr.AsciiLength * sizeof(short))) == NULL)
             return;

           lseek(fd, hdr.WidthTabOffset, SEEK_SET);
           read(fd, width, hdr.AsciiLength * sizeof(short));
        }
        else if(hdr.Flags & _FONT_MetricPerChar)
             {  if((metric = malloc(hdr.AsciiLength * sizeof(_FontMetricStruct))) == NULL)
                  return;

                lseek(fd, hdr.WidthTabOffset, SEEK_SET);
                read(fd, metric, hdr.AsciiLength * sizeof(_FontMetricStruct));
             }
             else
             {  return;
             }

        term_load();
        term_clear(TERM_CLS_SCR);
        ch = FindDef(-1, 1);
        DrawImage(ch);

        quit = edit = 0;

        while(!quit)
          switch(term_key())
          {  case K_LEFT:  if(edit)
                           {  if(posx > 0)
                                --posx;

                              term_cur(INDENT + posy, INDENT + posx);
                           }
                           else
                           {  ch = FindDef(ch, -1);
                              DrawImage(ch);
                           }
                           break;

             case K_RIGHT:  if(edit)
                            {  if(posx < szx - 1)
                                 ++posx;

                               term_cur(INDENT + posy, INDENT + posx);
                            }
                            else
                            {  ch = FindDef(ch, 1);
                               DrawImage(ch);
                            }
                            break;

             case K_UP:  if(edit)
                         {  if(posy > 0)
                              --posy;

                            term_cur(INDENT + posy, INDENT + posx);
                         }
                         else
                         {  ch = FindDef(ch, -1);
                            DrawImage(ch);
                         }
                         break;

             case K_DOWN:  if(edit)
                           {  if(posy < szy - 1)
                                ++posy;

                              term_cur(INDENT + posy, INDENT + posx);
                           }
                           else
                           {  ch = FindDef(ch, 1);
                              DrawImage(ch);
                           }
                           break;

             case K_ENTER:  if(edit = !edit)
                            {  dirty = 0;
                               posx = posy = 0;
                               term_printf(INDENT + szy + 1, 0, TERM_HILIGHT, "EDIT?");
                               term_clear(TERM_CLS_EOL);
                               term_cur(INDENT + posy, INDENT + posx);
                            }
                            else
                            {  if(dirty)
                                 SaveImage(ch);

                               term_printf(INDENT + szy + 1, 0, TERM_HILIGHT, "BROWSE?");
                               term_clear(TERM_CLS_EOL);
                            }
                            break;

             case ' ':  if(edit)
                        {  bit = posx & 0x7;
                           byte = bitmap[posy * bitmapbpl + (posx >> 3)] ^= (0x80 >> bit);
                           term_printf(INDENT + posy, INDENT + posx, TERM_NORMAL, (byte & (0x80 >> bit)) ? "*" : " ");
                           term_cur(INDENT + posy, INDENT + posx);
                           ++dirty;
                        }
                        break;

             case '0':  if(edit)
                        {  bit = posx & 0x7;
                           byte = bitmap[posy * bitmapbpl + (posx >> 3)] &= ~(0x80 >> bit);
                           term_printf(INDENT + posy, INDENT + posx, TERM_NORMAL, (byte & (0x80 >> bit)) ? "*" : " ");
                           term_cur(INDENT + posy, INDENT + posx);
                           ++dirty;
                        }
                        break;

             case '1':  if(edit)
                        {  bit = posx & 0x7;
                           byte = bitmap[posy * bitmapbpl + (posx >> 3)] |= (0x80 >> bit);
                           term_printf(INDENT + posy, INDENT + posx, TERM_NORMAL, (byte & (0x80 >> bit)) ? "*" : " ");
                           term_cur(INDENT + posy, INDENT + posx);
                           ++dirty;
                        }
                        break;

             case K_ESC:
             case 'q':
             case 'Q':  if(edit)
                        {  edit = 0;
                           DrawImage(ch);
                        }
                        else
                        {  ++quit;
                        }
                        break;

          }

        term_restore();
        close(fd);
    }

    /* __g_fontfile.h */

    /* _GR_FontStruct.Flags definitions     */
    #define _FONT_TypeMask          0x000F  /* Mask for font type           */
    #define _FONT_Bitmapped         0x0000  /* Font type: Bitmapped         */

    #define _FONT_IndexPerChar      0x0100
    #define _FONT_WidthPerChar      0x0200
    #define _FONT_MetricPerChar     0x0400  /* Metrics and Width are exclusive */

    #define _FS_Italic              0x0001
    #define _FS_Oblique             0x0002
    #define _FS_RevItalic           0x0004
    #define _FS_Bold                0x0010

    typedef struct {
        short               x, y;
    } _PointStruct;

    typedef struct {
        _PointStruct        Size;           /* Bytes per line == (Size.x+7)>>3  */
        signed char         BaseLinePos;
        signed char         LeftBearing;
        short               Width;
    } _FontMetricStruct;

    typedef struct {
        short               Status;         /* For a file, MUST be set to 'QW' */
        unsigned short      Flags;
        _PointStruct        Size;
        _PointStruct        Extent;
        unsigned short      Spare1;
        unsigned short      ImageOffset;
        unsigned short      BPChar;
        unsigned short      WidthTabOffset;
        unsigned short      Spare2[4];
        short               UnderLinePos;
        short               BaseLinePos;
        unsigned short      AsciiOffset;
        unsigned short      AsciiLength;
        char                Description;
    } _FontStruct;

    1.5 CAVEATS ABOUT A PHF
        -------------------

    bdf_2_phf ships with Photon.  You will want UNICODE BDF
    files (a MUST).  Try www.unicode.org as a starting point.
    One caveat, PHFs cannot be larger than 64k per file.
    Here is a script used to create a font, where size
    had to be manipulated.  The -S (start) and -N (amount) switches
    were modified to get each file <= 64k.

    If you encounter a font that requires it
    to be split up, you will have to put it in your
    extension list (fontcfg).  Non-asain BDF files usually
    do not need to be split up ...

    MAKEFONTS SCRIPT:

    #!/bin/sh
    #   Usage:  makefonts bdf_filename
    #
    # If you change the size, you'll probably have to modify
    # the ranges to keep the files below 64k apiece.

    SIZE=16
    BDF_FILE=something_big.bdf
    CMD_BDF2PHF=/usr/photon/bin/bdf_2_phf

        $CMD_BDF2PHF    -S0x20      -N0x1Fe0    -Ouk00-$SIZE.phf $BDF_FILE
        $CMD_BDF2PHF    -S0x2000    -N0xC00     -Ouk20-$SIZE.phf $BDF_FILE
        $CMD_BDF2PHF    -S0x3000    -N0x1000    -Ouk30-$SIZE.phf $BDF_FILE
        $CMD_BDF2PHF    -S0x4000    -N0x1600    -Ouk40-$SIZE.phf $BDF_FILE
        $CMD_BDF2PHF    -S0x5600    -N0x400     -Ouk56-$SIZE.phf $BDF_FILE
        $CMD_BDF2PHF    -S0x5a00    -N0x400     -Ouk5A-$SIZE.phf $BDF_FILE
        $CMD_BDF2PHF    -S0x5e00    -N0x500     -Ouk5E-$SIZE.phf $BDF_FILE
        $CMD_BDF2PHF    -S0x6300    -N0x500     -Ouk63-$SIZE.phf $BDF_FILE
        $CMD_BDF2PHF    -S0x6800    -N0x700     -Ouk68-$SIZE.phf $BDF_FILE
        $CMD_BDF2PHF    -S0x6F00    -N0x500     -Ouk6F-$SIZE.phf $BDF_FILE
        $CMD_BDF2PHF    -S0x7400    -N0x500     -Ouk74-$SIZE.phf $BDF_FILE
        $CMD_BDF2PHF    -S0x7900    -N0x500     -Ouk79-$SIZE.phf $BDF_FILE
        $CMD_BDF2PHF    -S0x7E00    -N0x500     -Ouk7E-$SIZE.phf $BDF_FILE
        $CMD_BDF2PHF    -S0x8300    -N0x500     -Ouk83-$SIZE.phf $BDF_FILE
        $CMD_BDF2PHF    -S0x8800    -N0x600     -Ouk88-$SIZE.phf $BDF_FILE
        $CMD_BDF2PHF    -S0x8E00    -N0x600     -Ouk8E-$SIZE.phf $BDF_FILE
        $CMD_BDF2PHF    -S0x9400    -N0x500     -Ouk94-$SIZE.phf $BDF_FILE

        $CMD_BDF2PHF    -S0x9900    -N0xA00     -Ouk99-$SIZE.phf $BDF_FILE
        $CMD_BDF2PHF    -S0xa300    -N0xA00     -OukA3-$SIZE.phf $BDF_FILE
        $CMD_BDF2PHF    -S0xad00    -N0x500     -OukAD-$SIZE.phf $BDF_FILE
        $CMD_BDF2PHF    -S0xb200    -N0x500     -OukB2-$SIZE.phf $BDF_FILE
        $CMD_BDF2PHF    -S0xb700    -N0x500     -OukB7-$SIZE.phf $BDF_FILE
        $CMD_BDF2PHF    -S0xbc00    -N0x500     -OukBC-$SIZE.phf $BDF_FILE
        $CMD_BDF2PHF    -S0xc100    -N0x500     -OukC1-$SIZE.phf $BDF_FILE
        $CMD_BDF2PHF    -S0xc600    -N0x500     -OukC6-$SIZE.phf $BDF_FILE
        $CMD_BDF2PHF    -S0xd000    -N0x500     -OukD0-$SIZE.phf $BDF_FILE
        $CMD_BDF2PHF    -S0xd500    -N0x1b00    -OukD5-$SIZE.phf $BDF_FILE

        $CMD_BDF2PHF    -S0xF000    -N0xFE6     -OukF0-$SIZE.phf $BDF_FILE