Back to index

tetex-bin  3.0
encoding.c
Go to the documentation of this file.
00001 /* MODULE encoding (encoding.c)
00002  * interface:  typedef char *encoding[256];
00003  *             void getenc(
00004  *                  char **fontname, **encname,  
00005  *                         ( foundry name of font and name of this encoding )
00006  *                    encoding ev,      output encoding
00007  *                    int width[256]);  output widths
00008  *
00009  * depends on: MODULEs binary_table, strings
00010  *             <ctype.h>
00011  *             <stdio.h>
00012  *             <stdlib.h>
00013  *             <string.h>
00014  *
00015  * globals:    void fatal();
00016  *
00017  * Author:     Piet Tutelaers
00018  *             Version 1.3 (August 1992)
00019  *             Version 1.4 (December 1993)
00020  */
00021 
00022 #include <ctype.h>
00023 #include <stdio.h>
00024 #include <stdlib.h>
00025 #include <string.h>
00026 #include "basics.h"
00027 
00028 char *my_string(char *);
00029 void remove_string();
00030 void addcc(char *name, int charcode);
00031 int getcc(char *name);
00032 void initcc();
00033 
00034 extern char *encfile, *afmfile;
00035 
00036 /* return a pointer to first non space character after occurence of string t,
00037  * the scan starts at pointer s 
00038  */
00039 static char *value_after(char *s, char *t)
00040 {  int l;
00041    l = strlen(t);
00042    for (;;) {
00043       while (*s != *t && *s != '\n') s++;
00044       if (*s == '\n') return NULL;
00045       if (strncmp(s, t, l) == 0) break;
00046       s++;
00047    }
00048    s += l;
00049    while (isspace(*s)) s++;
00050    return s;
00051 }
00052 
00053 int decimal(char *s)
00054 {  int sign = 1, d = 0;
00055 
00056    while (isspace(*s)) s++;
00057    if (*s == '-') { sign = -1; s++; }
00058    while (isdigit(*s)) { d = d * 10 + (*s - '0'); s++; }
00059    return sign*d;
00060 }
00061 
00062 /* Nextsymbol() reads lines from enc until a '[', '/' or a ']' is 
00063  * encountered. In that case pline points to the character following
00064  * this symbol otherwise a fatal error is generated.
00065  */
00066 
00067 FILE *enc;
00068 
00069 #define LINEBUF 1024
00070 char line[LINEBUF], *pline = NULL;
00071 
00072 char nextsymbol()
00073 {
00074    for (;;) {
00075       if (pline == NULL) {
00076          if (fgets(line, LINEBUF-1, enc) == NULL)
00077             fatal("unexpected EOF while reading %s\n", encfile);
00078          pline = line;
00079       }
00080       if (*pline == '[' || *pline == ']' || *pline == '/') break;
00081       if (*pline == '%' || *pline == '\n' || *pline == '\0') 
00082       {  pline = NULL; 
00083          continue; 
00084       }
00085       pline++;
00086    }
00087    pline++; return *(pline-1);
00088 }
00089 
00090 char *nextpsname()
00091 {  int i = 0;
00092    char the_nextname[MAXSTRLEN], *name;
00093 
00094    for (;;) {
00095       if (pline == NULL) {
00096          if (fgets(line, LINEBUF-1, enc) == NULL)
00097             fatal("unexpected EOF while reading %s\n", encfile);
00098          pline = line;
00099       }
00100       if (*pline == '%' || *pline == '\n' || *pline == '\0') 
00101       {  pline = NULL; 
00102          continue; 
00103       }
00104       if (isspace(*pline)) {
00105          pline++;
00106         continue;
00107       }
00108       if (!isalpha(*pline)) fatal("invalid name in %s\n", encfile);
00109       /* pt981009: added '_' Staszek Wawrykiewicz <staw@gust.org.pl> */
00110       while (isalnum(*pline) || *pline == '-' || *pline == '_') {
00111        if (i > MAXSTRLEN-2)
00112          fatal("name too long in %s (%s)\n", line, encfile);
00113        the_nextname[i++] = *pline++;
00114       }
00115       the_nextname[i] = '\0';
00116       name = malloc(i+1);
00117       if (name == NULL) fatal("Out of memory\n");
00118       strcpy(name, the_nextname);
00119       break;
00120    }
00121    /* pt981009: removed pline++ Staszek Wawrykiewicz <staw@gust.org.pl> */
00122    return name;
00123 }
00124 
00125 typedef char *encoding[256];
00126 
00127 void getenc(char **fontname, char **encname, encoding ev, int width[256])
00128 {  int i, len, SCMseen, Ccnt, wx, cc;
00129    FILE *afm;
00130    char *name, ns;
00131    
00132    for (i=0; i < 256; i++) { ev[i] = NULL; width[i] = -1000; }
00133    if (encfile) {
00134       enc = fopen(encfile, "r");
00135       if (enc == NULL) fatal("Can't open %s\n", encfile);
00136       if (nextsymbol() != '/') fatal("missing '/encoding' in %s\n", encfile);
00137       *encname = nextpsname();
00138       if (nextsymbol() != '[') fatal("missing '[' in %s\n", encfile);
00139       i = 0;
00140       while (i < 256 && (ns = nextsymbol()) == '/') {
00141          name = my_string(pline);
00142          if (strcmp(name, ".notdef") == 0) { 
00143             i++; remove_string();
00144             continue; 
00145          }
00146          addcc(name, i++);
00147       }
00148       if (i != 256) fatal("missing %d symbols in %s\n", 256-i, encfile);
00149       if (nextsymbol() != ']') fatal("missing ']' in %s\n", encfile);
00150       fclose(enc);
00151    }
00152    afm = fopen(afmfile, "r");
00153    if (afm == NULL) fatal("Can't open %s\n", afmfile);
00154    /*
00155     * Scan header of AFM file and take the FontName and EncodingScheme
00156     * (used for identification purposes in the PK postamble)
00157     * Stop after reading `StartCharMetrics'.
00158     */
00159    SCMseen = 0; Ccnt = 0;
00160    while (fgets(line, LINEBUF-1, afm)) {
00161       if (strncmp(line, "FontName", 8) == 0) { 
00162         pline = value_after(line, "FontName"); 
00163         len = strlen(pline);
00164         if (*(pline+len-1) == '\n') {
00165            *(pline+len-1) = '\0'; len--;
00166         }
00167         *fontname = malloc(len + 1);
00168         if (*fontname == NULL) fatal("Out of memory\n");
00169          strcpy(*fontname, pline);
00170       }
00171       else if (encname == NULL && strncmp(line, "EncodingScheme", 8) == 0) { 
00172         pline = value_after(line, "EncodingScheme"); 
00173         len = strlen(pline);
00174         if (*(pline+len-1) == '\n') {
00175            *(pline+len-1) = '\0'; len--;
00176         }
00177         *encname = malloc(len + 1);
00178         if (*encname == NULL) fatal("Out of memory\n");
00179         strcpy(*encname, pline);
00180       }
00181       else if (strncmp(line, "StartCharMetrics", 16) == 0) {
00182          SCMseen = 1; break;
00183       }
00184    }
00185    if (SCMseen == 0) fatal("%s: no metrics info\n", afmfile);
00186    while (fgets(line, LINEBUF-1, afm)) {
00187       if (strncmp(line, "EndCharMetrics", 14) == 0) break;
00188       if (strncmp(line, "C ", 2) != 0) 
00189          fatal("%s: unexpected line\n", afmfile);
00190 
00191       /* Gracefully terminate when the AFM file is not valid.  Every line */
00192       /* in the AFM file should specify a "C"haracter, a "WX"idth, and    */
00193       /* a "N"ame. (ndw)
00194       */
00195       pline = value_after(line, "C"); 
00196       if (pline == NULL)
00197          fatal("\nBad char metric in %s (no char):\n\t %s\n", afmfile, line);
00198       cc = decimal(pline);
00199       pline = value_after(pline, "WX"); 
00200       if (pline == NULL)
00201          fatal("\nBad char metric in %s (no width):\n\t %s\n", afmfile, line);
00202       wx = decimal(pline);
00203       pline = value_after(pline, "N"); 
00204       if (pline == NULL)
00205          fatal("\nBad char metric in %s (no name):\n\t %s\n", afmfile, line);
00206       name = my_string(pline);
00207       
00208       if (encfile) {
00209          if ((i = getcc(name)) == -1) {
00210             remove_string();
00211             continue;
00212         }
00213          do { /* allow more occurences per name */
00214             ev[i] = name; width[i] = wx;
00215             i = getcc(name);
00216          }
00217          while (i >= 0);
00218       }
00219       else if (cc >= 0 && cc <= 255) { /* ndw: 10/13/92 */
00220         ev[cc] = name; width[cc] = wx;
00221       }
00222       else if (cc > 255)
00223         msg("Char code %d ignored (out of range).\n", cc);
00224       Ccnt++;
00225    }
00226    if (Ccnt == 0) fatal("%s: no characters selected\n", afmfile);   
00227 }
00228 
00229 /* END MODULE encoding */
00230 
00231 /* MODULE binary_table
00232  * depends on: MODULE string
00233  *             <stdlib.h>
00234  *             <string.h>
00235  */
00236 
00237 /*
00238  * TUG has accepted an extended font layout (EC.enc) where the hyphen 
00239  * occupies two positions ('055 and '177) to handle exeptional hyphenation
00240  * situations (see TUGboat#11 1990 (no. 4) pp. 514).
00241  * To handle this special case we allow two charcodes per symbol.
00242  */
00243   
00244 /*
00245  * Two functions for a binary search table. One to add a name and one 
00246  * to lookup a name. This table is used to store all encoding names and 
00247  * its corresponding charcode.
00248  */
00249 
00250 struct Node
00251 { char *name;                    /* pointer to a PostScript string */
00252   short cc[2];                   /* its charcode's (maximum of two) */
00253   short left, right;
00254 } node[256];
00255 
00256 static int freenode = 0;
00257 static short root = -1;
00258 
00259 void addcc(char *name, int charcode)
00260 {  short r, p, q;
00261 
00262    q = root;
00263    while (q != -1) {
00264       p = q; r = strcmp(name, node[p].name);
00265       if (r == 0) {
00266         if (node[p].cc[1] == -1) {
00267            node[p].cc[1] = charcode;
00268            return;
00269         }
00270         else 
00271            fatal("%s: more than two codes for %s (%d,%d,%d)\n", 
00272               encfile, name, node[p].cc[0], node[p].cc[1], charcode);
00273       }
00274       else if (r < 0) q=node[p].left;
00275       else q=node[p].right;
00276    }
00277    if (freenode == 256) 
00278       fatal("%s: too many PostScript names\n", encfile);
00279       /* not found hence insert */
00280    node[freenode].name = name;
00281    node[freenode].cc[0] = charcode;
00282    node[freenode].cc[1] = -1;
00283    node[freenode].left = node[freenode].right = -1;
00284    if (root == -1)
00285       root = freenode;
00286    else {
00287       if (r < 0) node[p].left=freenode;
00288       else node[p].right=freenode;
00289    }
00290    freenode++;
00291 }
00292 
00293 int getcc(char *name)
00294 {  short r, p, q, cc;
00295 
00296    q = root;
00297    while (q != -1) {
00298       p = q; r = strcmp(name, node[p].name);
00299       if (r == 0) {
00300         cc = node[p].cc[0];
00301         node[p].cc[0] = node[p].cc[1];
00302         node[p].cc[1] = -1;
00303         return cc; 
00304       }
00305       else if (r < 0) q = node[p].left;
00306       else q = node[p].right;
00307    }
00308    return -1;
00309 }
00310 
00311 /* END MODULE binary_table */
00312 
00313 /* MODULE string: 
00314  * depends on: <ctype.h>
00315  *             <string.h>
00316  */
00317 
00318 /* String() reads a string starting at a given character pointer. 
00319  * After removing leading whitespace the resulting string (with possible
00320  * `.' and '_' characters) is stored in a stringpool after which a pointer 
00321  * to it is returned.
00322  */
00323 
00324 #define POOLSIZE 10000
00325 static char stringpool[POOLSIZE];
00326 static int poolsize,      /* occupied space annex free index */
00327            lastpoolsize;  /* previous poolsize */
00328 
00329 char *my_string(char *s)
00330 {  int length; char *str;
00331 
00332    while (isspace(*s)) s++;
00333    str = s; length = 0;
00334    while (isalnum(*s) || *s == '.' || *s == '_') { length++; s++; }
00335    if (length == 0) return NULL;
00336    else {
00337       if (length + 1 > POOLSIZE - poolsize)
00338          fatal("Out of memory %s\n", s);
00339       strncpy(stringpool+poolsize, str, length);
00340       str = stringpool + poolsize;
00341       s = stringpool + poolsize + length;
00342       *s = '\0';
00343       lastpoolsize = poolsize;
00344       poolsize += length+1;
00345       return str; 
00346    }
00347 }
00348 
00349 /* remove last string from stringpool */
00350 void remove_string()
00351 {
00352    poolsize = lastpoolsize;
00353 }
00354 
00355 /* END MODULE string */
00356