home *** CD-ROM | disk | FTP | other *** search
/ Geek Gadgets 1 / ADE-1.bin / ade-dist / unixtex-6.1b-src.tgz / tar.out / contrib / unixtex / dviljk / tfm.c < prev   
C/C++ Source or Header  |  1996-09-28  |  8KB  |  255 lines

  1. /* tfm.c -- read tfm widths resident font support in dvilj. Originally
  2.    written by kb@cs.umb.edu in early 1994. Public domain. */
  3.  
  4. #define KPATHSEA
  5. #ifdef KPATHSEA
  6. #include <kpathsea/config.h>
  7. #include <kpathsea/c-fopen.h>
  8. #include <kpathsea/lib.h>
  9. #include <kpathsea/tex-file.h>
  10. #else
  11. #include <stdio.h>
  12. extern char* TFMpath;
  13. #endif
  14.  
  15. #include "config.h" /* for STRSIZE and tfm_info_type, at least */
  16.  
  17. #ifdef vms
  18. #include <ssdef.h>
  19. #include <stsdef.h>
  20. #define getenv vms_getenv
  21. #endif
  22.  
  23. /* Defined in dvi2xx.c. */
  24. extern long NoSignExtend ();
  25. #define TFM_GET_TWO()  NoSignExtend (tfm_fp, 2)
  26. #define TFM_GET_FOUR() NoSignExtend (tfm_fp, 4)
  27. extern bool G_quiet;
  28. extern void Warning();
  29.  
  30. /* Defined in xmalloc.c. */
  31. extern void *xmalloc ();
  32.  
  33.  
  34. /* Read N words (N * 4 bytes) from TFM_FP and return it in *OUTBUF, unless
  35.    OUTBUF==NULL, in which case throw them away. */
  36.  
  37. static void
  38. tfm_get_n (tfm_fp, nwords, outbuf)
  39.     FILE *tfm_fp;
  40.     unsigned nwords;
  41.     void **outbuf;
  42. {
  43.   unsigned n = nwords * 4;
  44.   void *buf = (void *) xmalloc (n);
  45.  
  46.   if (fread (buf, n, 1, tfm_fp) != 1) {
  47.     fprintf (stderr, "dvi2xx: Could not read %u bytes from TFM file.\n", n);
  48.     exit (1);
  49.   }
  50.  
  51.   /* If OUTBUF is null, free what we just read, else return it. */
  52.   if (outbuf) {
  53.     *outbuf = buf;
  54.   } else {
  55.     free (buf);
  56.   }
  57. }
  58.  
  59.  
  60. /* Read a string in BCPL format from DATA into STR, and terminate with a
  61.    null byte. First byte of DATA says how many characters follow.
  62.    Assume STR is long enough.  */
  63.  
  64. static void
  65. get_bcpl (data, str)
  66.     unsigned char *data;
  67.     unsigned char *str;
  68. {
  69.   unsigned length;
  70.   
  71.   for (length = *(data ++); length; length --) {
  72.     *(str ++) = *(data ++);
  73.   }
  74.  *str = 0;
  75. }
  76.  
  77. /* Header word 18:
  78.      2 bytes: "KN" for Karl and Norm---this identifies our extensions
  79.      1 byte : 1 if proportional, 0 otherwise
  80.      1 byte : reserved (to extend the style, if necessary)
  81.    Header word 19:
  82.      2 bytes: PCL style selection number
  83.      1 byte : reserved (to extend weight, if necessary)
  84.      1 byte : weight (signed, 2's complement, valid -7 to +7)
  85.    Header word 20:
  86.      2 bytes: reserved (to extend typeface id, if necessary)
  87.      2 bytes: PCL typeface selection number
  88.    
  89.    The first (BigEndian) byte of header word #18 is DATA[0].
  90.    Assume DATA is long enough for everything we might try to read. */
  91.  
  92. static bool
  93. get_pcl_info (data, spacing, style, weight, typeface_id)
  94.     unsigned char *data;
  95.     unsigned *spacing;
  96.     unsigned *style;
  97.     int *weight;
  98.     unsigned *typeface_id;
  99. {
  100.   /* No magic number for our extensions => forget it. */
  101.   if (data[0] != 'K' && data[1] != 'N')
  102.     return _FALSE;
  103.  
  104.   *spacing = data[(0* 4) + 2]; /* Third byte of first word. */
  105.   
  106.   /* First two bytes of second word. */
  107.   *style = (data[(1 * 4)] << 8) + data[(1 * 4) + 1];
  108.   
  109.   /* Last byte of second word, signed two-complement. */
  110.   *weight = data[(1 * 4) + 3];
  111.   if (*weight >= 128) *weight -= 256;
  112.   
  113.   /* Effectively all four bytes of third word. */
  114.   *typeface_id = (data[(2 * 4) + 0] << 24) + (data[(2 * 4) + 1] << 16)
  115.                + (data[(2 * 4) + 2] << 8)  + (data[(2 * 4) + 3]);
  116.  
  117.   return _TRUE;
  118. }
  119.  
  120. /* If the TFM file NAME exists, set the elements of RET and return true.
  121.    Otherwise, return false.  */
  122.  
  123. bool
  124. tfm_read_info (name, ret)
  125.     char *name;
  126.     tfm_info_type *ret;
  127. {
  128.   /* Don't use a structure for this, since then it might occupy more
  129.      than the exactly four bytes that we need. */
  130.   unsigned char *char_info;
  131.   FILE *tfm_fp;
  132.   unsigned char *header_data;
  133.   unsigned char *width_raw; /* array of 1-byte data */
  134.   unsigned long4 *width_table; /* array of 4-byte fixes */
  135.   unsigned i;
  136.   unsigned lh, bc, ec, nw, nh, nd, ni, nl, nk, ne, np;
  137. #ifdef KPATHSEA
  138.   char *full_name = kpse_find_tfm (name);
  139.  
  140.   if (full_name == NULL) {
  141.     return _FALSE;
  142.   }
  143.   tfm_fp = xfopen (full_name, FOPEN_RBIN_MODE);
  144. #else /* not KPATHSEA */
  145.   char full_name[STRSIZE];
  146.   if (findfile(TFMpath, name, NULL, full_name, _TRUE, 0)) {
  147.  
  148.     /* fprintf(stderr,"full_name=<%s>\n", full_name);*/
  149.     tfm_fp = fopen (full_name, READ_BINARY);
  150.     if (tfm_fp == NULL) {
  151.       /* this can happen, if the calculation for max number of open
  152.        * files has to be corrected
  153.        */
  154.       fprintf(stderr,"Error: file <%s> could not be opened\n", full_name);
  155.       return _FALSE;
  156.     }
  157.   } else {
  158.     Warning("tfm file %s.tfm not found on path <%s>\n", name, TFMpath);
  159.     return _FALSE;
  160.   }
  161. #endif /* not KPATHSEA */
  162.  
  163.   (void) TFM_GET_TWO ();   /* word length of file */
  164.   lh = TFM_GET_TWO ();     /* words of header data */
  165.   bc = TFM_GET_TWO ();     /* smallest character code */
  166.   ec = TFM_GET_TWO ();     /* largest character code */
  167.   nw = TFM_GET_TWO ();     /* words in width table */
  168.   nh = TFM_GET_TWO ();     /* words in height table */
  169.   nd = TFM_GET_TWO ();     /* words in depth table */
  170.   ni = TFM_GET_TWO ();     /* words in italic correction table */
  171.   nl = TFM_GET_TWO ();     /* words in lig/kern table */
  172.   nk = TFM_GET_TWO ();     /* words in kern table */
  173.   ne = TFM_GET_TWO ();     /* words in extensible char table */
  174.   np = TFM_GET_TWO ();     /* words of font parameter data */
  175.  
  176.   tfm_get_n (tfm_fp, lh, &header_data);
  177.   /* Only two headerbyte words are required by the TFM format, so don't
  178.      insist on all this extra stuff. */
  179.   if (lh > 2) {
  180.     get_bcpl (header_data + (2 * 4), ret->coding_scheme);
  181.   } else {
  182.     ret->coding_scheme[0] = 0;
  183.   }
  184.   
  185.   if (lh > 12) {
  186.     get_bcpl (header_data + (12 * 4), ret->family);
  187.   } else {
  188.     ret->family[0] = 0;
  189.   }
  190.  
  191.   /* Sorry for the convoluted logic. The idea is that if the family
  192.      is HPAUTOTFM, we better have our extensions -- so if we don't
  193.      have enough header words, or if we don't find what we need in
  194.      the header words, something's seriously wrong, and we shouldn't
  195.      claim to have succeeded at reading a good TFM file.  */
  196.   if (strcmp (ret->family, "HPAUTOTFM") == 0
  197.       && (lh < 20
  198.           || !get_pcl_info (&(header_data[18 * 4]),
  199.                             &ret->spacing, &ret->style, &ret->weight,
  200.                             &ret->typeface_id))) {
  201.     fclose (tfm_fp);
  202.     return _FALSE;
  203.   }
  204.  
  205.   /* Initialize our returned array of widths to zero, since the TFM file
  206.      need not contain info for all character codes. */
  207.   for (i = 0; i < bc; i++) {
  208.     ret->widths[i] = 0;
  209.   }
  210.   for (i = ec + 1; i < 256; i++) {
  211.     ret->widths[i] = 0;
  212.   }
  213.   
  214.   /* The char_info is one word (four bytes) for each character in the font. */
  215.   tfm_get_n (tfm_fp, ec - bc + 1, &char_info);
  216.   
  217.   /* The width table is just nw words. */
  218.   tfm_get_n (tfm_fp, nw, &width_raw);
  219.   width_table = (unsigned long4 *) xmalloc (nw * 4);
  220.  
  221.   /* But the width table contains four-byte numbers, so have to convert
  222.      from BigEndian to host order. */
  223.   for (i = 0; i < nw; i++) {
  224.     unsigned byte_offset = i * 4;
  225.     unsigned b1 = width_raw[byte_offset];
  226.     unsigned b2 = width_raw[byte_offset + 1];
  227.     unsigned b3 = width_raw[byte_offset + 2];
  228.     unsigned b4 = width_raw[byte_offset + 3];
  229.     width_table[i] = (b1 << 24) + (b2 << 16) + (b3 << 8) + b4;
  230.   }
  231.  
  232.   /* For each character, retrieve and store the TFM width. */
  233.   for (i = bc; i <= ec; i++) {
  234.     unsigned char w_i = char_info[(i - bc) * 4];
  235.     ret->widths[i] = width_table[w_i];
  236.   }
  237.  
  238.   /* Throw away everything up to the second font parameter. (Could just
  239.      seek, but I don't want to pull in the include files, etc.) */
  240.   if (np >= 2) {
  241.     tfm_get_n (tfm_fp, nh + nd + ni + nl + nk + ne + 1, NULL);
  242.     ret->interword = TFM_GET_FOUR ();
  243.   } else {
  244.     ret->interword = 0;
  245.   }
  246.  
  247.   free (header_data);
  248.   free (char_info);
  249.   free (width_raw);
  250.   free (width_table);
  251.   
  252.   fclose (tfm_fp);
  253.   return _TRUE;
  254. }
  255.