Logo Search packages:      
Sourcecode: kbd version File versions  Download package

psfxtable.c

/*
 * psfxtable.c
 *
 * Manipulate headers and Unicode tables for psf fonts
 *
 * Copyright (C) 1999 Andries E. Brouwer
 *  derived from sources that were
 * Copyright (C) 1994 H. Peter Anvin
 *
 * This program may be freely copied under the terms of the GNU
 * General Public License (GPL), version 2, or at your option
 * any later version.
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <sysexits.h>
#include "nls.h"
#include "version.h"
#include "psf.h"
#include "xmalloc.h"
#include "psffontop.h"

/*
 * call: psfxtable -i infont -o outfont -it intable -ot outtable
 *       psfaddtable infont intable [outfont]
 *     psfgettable infont [outtable]
 *     psfstriptable infont [outfont]
 *
 * When outfont is requested it will get psf1 header when
 * infont had psf1 header and intable does not have sequences
 * and psf2 header otherwise.
 */

/*
 * Parse humanly readable unicode table.
 * Format: lines
 *   <fontposition><tab><uc_defs>
 * or
 *   <fontrange><tab><uc_defs>
 * or
 *   <fontrange><tab><uc_range>
 *  where
 *   <uc_defs> :: <empty> | <uc_def><space><uc_defs>
 *   <uc_def> :: <uc> | <uc>,<uc_def>
 *   <uc> :: U+<h><h><h><h>
 *   <h> :: <hexadecimal digit>
 *   <range> :: <value>-<value>
 *  Blank lines and lines starting with # are ignored.
 */
struct unicode_list *uclistheads;

static void
addpair(int fontpos, unsigned int uc) {
      struct unicode_list *ul;
      struct unicode_seq *us;

      ul = xmalloc(sizeof(struct unicode_list));
      us = xmalloc(sizeof(struct unicode_seq));
      us->uc = uc;
      us->prev = us;
      us->next = NULL;
      ul->seq = us;
      ul->prev = uclistheads[fontpos].prev;
      ul->prev->next = ul;
      ul->next = NULL;
      uclistheads[fontpos].prev = ul;
}

static void
addseq(int fontpos, unsigned int uc) {
      struct unicode_list *ul;
      struct unicode_seq *us;

      ul = uclistheads[fontpos].prev;
      us = xmalloc(sizeof(struct unicode_seq));
      us->uc = uc;
      us->prev = ul->seq->prev;
      us->prev->next = us;
      us->next = NULL;
      ul->seq->prev = us;
}

static int
getunicode(char **p0) {
      char *p = *p0;

      while (*p == ' ' || *p == '\t')
            p++;
      if (*p != 'U' || p[1] != '+' ||
          !isxdigit(p[2]) || !isxdigit(p[3]) || !isxdigit(p[4]) ||
          !isxdigit(p[5]) || isxdigit(p[6]))
            return -1;
      *p0 = p+6;
      return strtol(p+2,0,16);
}

static void
parse_itab_line(char *buf, int fontlen){
      char *p, *p1;
      int i;
      long fp0, fp1, un0, un1;

      if ((p = strchr(buf, '\n')) != NULL)
            *p = 0;
      else {
            char *u = _("%s: Warning: line too long\n");
            fprintf(stderr, u, progname);
            exit(EX_DATAERR);
      }

      p = buf;

      while (*p == ' ' || *p == '\t')
            p++;
      if (!*p || *p == '#')
            return;

      fp0 = strtol(p, &p1, 0);
      if (p1 == p) {
            char *u = _("%s: Bad input line: %s\n");
            fprintf(stderr, u, progname, buf);
            exit(EX_DATAERR);
      }
      p = p1;

      if (*p == '-') {
            p++;
            fp1 = strtol(p, &p1, 0);
            if (p1 == p) {
                  char *u = _("%s: Bad input line: %s\n");
                  fprintf(stderr, u, progname, buf);
                  exit(EX_DATAERR);
            }
            p = p1;
      } else
            fp1 = 0;

      if (fp0 < 0 || fp0 >= fontlen) {
            char *u = _("%s: Glyph number (0x%lx) past end of font\n");
            fprintf(stderr, u, progname, fp0);
            exit(EX_DATAERR);
      }
      if (fp1 && (fp1 < fp0 || fp1 >= fontlen)) {
            char *u = _("%s: Bad end of range (0x%lx)\n");
            fprintf(stderr, u, progname, fp1);
            exit(EX_DATAERR);
      }

      if (fp1) {
            /* we have a range; expect the word "idem"
               or a Unicode range of the same length */
            while (*p == ' ' || *p == '\t')
                  p++;
            if (!strncmp(p, "idem", 4)) {
                  for (i = fp0; i <= fp1; i++)
                        addpair(i,i);
                  p += 4;
            } else {
                  un0 = getunicode(&p);
                  while (*p == ' ' || *p == '\t')
                        p++;
                  if (*p != '-') {
                        char *u = _("%s: Corresponding to a range of "
                                  "font positions, there should be "
                                  "a Unicode range\n");
                        fprintf(stderr, u, progname);
                        exit(EX_DATAERR);
                  }
                  p++;
                  un1 = getunicode(&p);
                  if (un0 < 0 || un1 < 0) {
                        char *u = _("%s: Bad Unicode range "
                                  "corresponding to font position "
                                  "range 0x%x-0x%x\n");
                        fprintf(stderr, u, progname, fp0, fp1);
                        exit(EX_DATAERR);
                  }
                  if (un1 - un0 != fp1 - fp0) {
                        char *u = _("%s: Unicode range U+%x-U+%x not "
                                  "of the same length as font "
                                  "position range 0x%x-0x%x\n");
                        fprintf(stderr, u, progname,
                              un0, un1, fp0, fp1);
                        exit(EX_DATAERR);
                  }
                  for (i = fp0; i <= fp1; i++)
                        addpair(i, un0-fp0+i);
            } /* not idem */
      } else {  /* no range */
            while ((un0 = getunicode(&p)) >= 0) {
                  addpair(fp0, un0);
                  while (*p++ == ',' && (un1 = getunicode(&p)) >= 0) {
                        addseq(fp0, un1);
                  }
                  p--;
            }
            while (*p == ' ' || *p == '\t')
                  p++;
            if (*p && *p != '#') {
                  char *u = _("%s: trailing junk (%s) ignored\n");
                  fprintf(stderr, u, progname, p);
            }
      }
}

static void
read_itable(FILE *itab, int fontlen, struct unicode_list **uclistheadsp) {
      char buf[65536];
      int i;

      if (uclistheadsp) {
            *uclistheadsp = xrealloc(*uclistheadsp,
                               fontlen*sizeof(struct unicode_list));
            for (i=0; i<fontlen; i++) {
                  struct unicode_list *up = &((*uclistheadsp)[i]);
                  up->next = NULL;
                  up->seq = NULL;
                  up->prev = up;
            }
            while (fgets(buf, sizeof(buf), itab) != NULL)
                  parse_itab_line(buf, fontlen);
      }
}

int
main(int argc, char **argv) {
      char *ifname, *ofname, *itname, *otname;
      FILE *ifil, *ofil, *itab, *otab;
      int psftype, fontlen, charsize, hastable, notable;
      int i;
      int width = 8, bytewidth, height;
      char *inbuf, *fontbuf;
      int inbuflth, fontbuflth;

      set_progname(argv[0]);

      setlocale(LC_ALL, "");
      bindtextdomain(PACKAGE, LOCALEDIR);
      textdomain(PACKAGE);

      if (argc == 2 && !strcmp(argv[1], "-V"))
            print_version_and_exit();

      ifil = ofil = itab = otab = NULL;
      ifname = ofname = itname = otname = NULL;
      fontbuf = NULL;
      notable = 0;

      if (!strcmp(progname, "psfaddtable")) {
            /* Do not send binary data to stdout without explicit "-" */
            if (argc != 4) {
                  char *u = _("Usage:\n\t%s infont intable outfont\n");
                  fprintf(stderr, u, progname);
                  exit(EX_USAGE);
            }
            ifname = argv[1];
            itname = argv[2];
            ofname = argv[3];
      } else if (!strcmp(progname, "psfgettable")) {
            if (argc < 2 || argc > 3) {
                  char *u = _("Usage:\n\t%s infont [outtable]\n");
                  fprintf(stderr, u, progname);
                  exit(EX_USAGE);
            }
            ifname = argv[1];
            otname = (argc == 3) ? argv[2] : "-";
      } else if (!strcmp(progname, "psfstriptable")) {
            /* Do not send binary data to stdout without explicit "-" */
            if (argc != 3) {
                  char *u = _("Usage:\n\t%s infont outfont\n");
                  fprintf(stderr, u, progname);
                  exit(EX_USAGE);
            }
            ifname = argv[1];
            ofname = argv[2];
            notable = 1;
      } else {
            for (i = 1; i < argc; i ++) {
                  if ((!strcmp(argv[i], "-i") || !strcmp(argv[i], "-if"))
                      && i < argc-1)
                        ifname = argv[++i];
                  else if((!strcmp(argv[i],"-o")||!strcmp(argv[i],"-of"))
                        && i < argc-1)
                        ofname = argv[++i];
                  else if(!strcmp(argv[i], "-it") && i < argc-1)
                        itname = argv[++i];
                  else if(!strcmp(argv[i], "-ot") && i < argc-1)
                        otname = argv[++i];
                  else if(!strcmp(argv[i], "-nt"))
                        notable = 1;
                  else
                        break;
            }
            if (i < argc || argc <= 1) {
                  char *u = _("Usage:\n\t%s [-i infont] [-o outfont] "
                            "[-it intable] [-ot outtable] [-nt]\n");
                  fprintf(stderr, u, progname);
                  exit(EX_USAGE);
            }
      }

      if (!ifname)
            ifname = "-";
      if (!strcmp(ifname, "-"))
            ifil = stdin;
      else {
            ifil = fopen(ifname, "r");
            if (!ifil) {
                  perror(ifname);
                  exit(EX_NOINPUT);
            }
      }

      if (!itname)
            /* nothing */;
      else if (!strcmp(itname, "-"))
            itab = stdin;
      else {
            itab = fopen(itname, "r");
            if (!itab) {
                  perror(itname);
                  exit(EX_NOINPUT);
            }
      }

      /* Refuse ifil == itab == stdin ? Perhaps not. */

      if (!ofname)
            /* nothing */;
      else if (!strcmp(ofname, "-"))
            ofil = stdout;
      else {
            ofil = fopen(ofname, "w");
            if (!ofil) {
                  perror(ofname);
                  exit(EX_CANTCREAT);
            }
      }

      if (!otname)
            /* nothing */;
      else if (!strcmp(otname, "-"))
            otab = stdout;
      else {
            otab = fopen(otname, "w");
            if (!otab) {
                  perror(otname);
                  exit(EX_CANTCREAT);
            }
      }

      if (readpsffont(ifil, &inbuf, &inbuflth, &fontbuf, &fontbuflth,
                  &width, &fontlen, 0,
                  itab ? NULL : &uclistheads) == -1) {
            char *u = _("%s: Bad magic number on %s\n");
            fprintf(stderr, u, progname, ifname);
            exit(EX_DATAERR);
      }
      fclose(ifil);

      charsize = fontbuflth/fontlen;
      bytewidth = (width + 7)/8;
      if (!bytewidth)
            bytewidth = 1;
      height = charsize / bytewidth;

      hastable = (uclistheads != NULL);

      if (PSF1_MAGIC_OK((unsigned char *)inbuf)) {
            psftype = 1;
      } else if (PSF2_MAGIC_OK((unsigned char *)inbuf)) {
            psftype = 2;
      } else {
            char *u = _("%s: psf file with unknown magic\n");
            fprintf(stderr, u, progname);
            exit(EX_DATAERR);
      }

      if (itab) {
            read_itable(itab, fontlen, &uclistheads);
            fclose(itab);
      }

      if (otab) {
            struct unicode_list *ul;
            struct unicode_seq *us;
            char *sep;

            if (!hastable) {
                  char *u = _("%s: input font does not have an index\n");
                  fprintf(stderr, u, progname);
                  exit(EX_DATAERR);
            }
            fprintf(otab,
                  "#\n# Character table extracted from font %s\n#\n",
                  ifname);
            for (i=0; i<fontlen; i++) {
                  fprintf(otab, "0x%03x\t", i);
                  sep = "";
                  ul = uclistheads[i].next;
                  while (ul) {
                        us = ul->seq;
                        while(us) {
                              fprintf(otab, "%sU+%04x", sep, us->uc);
                              us = us->next;
                              sep = ", ";
                        }
                        ul = ul->next;
                        sep = " ";
                  }
                  fprintf(otab, "\n");
            }
            fclose(otab);
      }

      if (ofil) {
            writepsffont(ofil, fontbuf, width, height, fontlen, psftype,
                       notable ? NULL : uclistheads);
            fclose(ofil);
      }

      return EX_OK;
}

Generated by  Doxygen 1.6.0   Back to index