0.99
[platform/upstream/kbd.git] / src / psfaddtable.c
1 /*
2  * psfaddtable.c
3  *
4  * Add a Unicode character table to a PSF font
5  *
6  * Copyright (C) 1994 H. Peter Anvin
7  *
8  * This program may be freely copied under the terms of the GNU
9  * General Public License (GPL), version 2, or at your option
10  * any later version.
11  *
12  * Added input ranges, aeb.
13  */
14
15 #include <stdio.h>
16 #include <stdlib.h>
17 #include <sysexits.h>
18 #include <string.h>
19 #include <ctype.h>
20 #include "psf.h"
21 #include "nls.h"
22
23 typedef unsigned short unicode;
24
25 struct unicode_list
26 {
27   unicode uc;                   /* Unicode listed */
28   struct unicode_list *next;
29 };
30
31 void usage(char *argv0)
32 {
33   fprintf(stderr, _("Usage: \n"
34                   "        %s psffont chartable [outfile]\n"), argv0);
35   exit(EX_USAGE);
36 }
37
38 int getunicode(char **p0)
39 {
40   char *p = *p0;
41
42   while (*p == ' ' || *p == '\t')
43     p++;
44   if (*p != 'U' || p[1] != '+' ||
45       !isxdigit(p[2]) || !isxdigit(p[3]) || !isxdigit(p[4]) ||
46       !isxdigit(p[5]) || isxdigit(p[6]))
47     return -1;
48   *p0 = p+6;
49   return strtol(p+2,0,16);
50 }
51
52 struct unicode_list **hookptr[512];
53
54 void addpair(int fp, int un)
55 {
56   struct unicode_list *newmbr;
57
58   if ( un != PSF_SEPARATOR && un <= 0xFFFF )
59     {
60         /* Add to linked list IN ORDER READ */
61                       
62         newmbr = malloc(sizeof(struct unicode_list));
63         newmbr->uc = (unicode) un;
64         newmbr->next = NULL;
65         *(hookptr[fp]) = newmbr;
66         hookptr[fp] = &(newmbr->next);
67     }
68   /* otherwise: ignore */
69 }
70
71 int main(int argc, char *argv[])
72 {
73   FILE *in, *ctbl, *out;
74   char *inname, *tblname;
75   char buffer[65536];
76   unsigned char unicodepair[2];
77   struct unicode_list *unilist[512];
78   struct unicode_list *newmbr, tmpmbr;
79   struct psf_header psfhdr;
80   int fontlen;
81   int i;
82   int fp0, fp1, un0, un1;
83   char *p, *p1;
84
85   setlocale(LC_ALL, "");
86   bindtextdomain(PACKAGE, LOCALEDIR);
87   textdomain(PACKAGE);
88
89   if ( argc < 3 || argc > 4 )
90     usage(argv[0]);
91
92   if ( !strcmp(argv[1],"-") )
93     {
94       in = stdin;
95       inname = "stdin";
96     }
97   else
98     {
99       in = fopen(inname = argv[1], "r");
100       if ( !in )
101         {
102           perror(inname);
103           exit(EX_NOINPUT);
104         }
105     }
106
107   if ( !strcmp(argv[2],"-") && in != stdin )
108     {
109       ctbl = stdin;
110       tblname = "stdin";
111     }
112   else
113     {
114       ctbl = fopen(tblname = argv[2], "r");
115       if ( !ctbl )
116         {
117           perror(tblname);
118           exit(EX_NOINPUT);
119         }
120     }
121
122   if ( argc < 4 || !strcmp(argv[3],"-") )
123     out = stdout;
124   else
125     {
126       out = fopen(argv[3], "w");
127       if ( !out )
128         {
129           perror(argv[3]);
130           exit(EX_CANTCREAT);
131         }
132     }
133
134   if ( fread(&psfhdr, sizeof(struct psf_header), 1, in) < 1 )
135     {
136       fprintf(stderr, _("%s: Cannot read psf header\n"), inname);
137       exit(EX_DATAERR);
138     }
139
140   if (! PSF_MAGIC_OK(psfhdr) )
141     {
142       fprintf(stderr, _("%s: Bad magic number\n"), inname);
143       exit(EX_DATAERR);
144     }
145
146   if ( psfhdr.mode > PSF_MAXMODE )
147     {
148       fprintf(stderr, _("%s: Unknown mode number (%d)\n"), inname, psfhdr.mode);
149       exit(EX_DATAERR);
150     }
151
152   fontlen = ( psfhdr.mode & PSF_MODE512 ) ? 512 : 256;
153
154   /* Copy font data */
155   if ( fread(buffer, psfhdr.charsize, fontlen, in) < fontlen )
156     {
157       perror(inname);
158       exit(EX_DATAERR);
159     }
160   fclose(in);                   /* Done with input */
161
162   /* Set has-table bit in mode field, and copy to output */
163   
164   psfhdr.mode |= PSF_MODEHASTAB;
165   fwrite(&psfhdr, sizeof(struct psf_header), 1, out);
166   fwrite(buffer, psfhdr.charsize, fontlen, out);
167
168   /* Now we come to the tricky part.  Parse the input table. */
169
170   for ( i = 0 ; i < 512 ; i++ ) /* Initialize unicode list */
171     unilist[i] = NULL;
172
173   for ( i = 0 ; i < 512 ; i++ ) /* Initialize hook pointer list */
174     hookptr[i] = &(unilist[i]);
175
176   while ( fgets(buffer, sizeof(buffer), ctbl) != NULL )
177     {
178       if ( (p = strchr(buffer, '\n')) != NULL )
179         *p = '\0';
180       else
181         fprintf(stderr, _("%s: Warning: line too long\n"), tblname);
182
183       p = buffer;
184
185 /*
186  * Syntax accepted:
187  *      <fontpos>       <unicode> <unicode> ...
188  *      <range>         idem
189  *      <range>         <unicode range>
190  *
191  * where <range> ::= <fontpos>-<fontpos>
192  * and <unicode> ::= U+<h><h><h><h>
193  * and <h> ::= <hexadecimal digit>
194  */
195
196       while (*p == ' ' || *p == '\t')
197         p++;
198       if (!*p || *p == '#')
199         continue;       /* skip comment or blank line */
200
201       fp0 = strtol(p, &p1, 0);
202       if (p1 == p)
203         {
204           fprintf(stderr, _("Bad input line: %s\n"), buffer);
205           exit(EX_DATAERR);
206         }
207       p = p1;
208
209       while (*p == ' ' || *p == '\t')
210         p++;
211       if (*p == '-')
212         {
213           p++;
214           fp1 = strtol(p, &p1, 0);
215           if (p1 == p)
216             {
217               fprintf(stderr, _("Bad input line: %s\n"), buffer);
218               exit(EX_DATAERR);
219             }
220           p = p1;
221         }
222       else
223         fp1 = 0;
224
225       if ( fp0 < 0 || fp0 >= fontlen )
226         {
227             fprintf(stderr,
228                     _("%s: Glyph number (0x%x) larger than font length\n"),
229                     tblname, fp0);
230             exit(EX_DATAERR);
231         }
232       if ( fp1 && (fp1 < fp0 || fp1 >= fontlen) )
233         {
234             fprintf(stderr,
235                     _("%s: Bad end of range (0x%x)\n"),
236                     tblname, fp1);
237             exit(EX_DATAERR);
238         }
239
240       if (fp1)
241         {
242           /* we have a range; expect the word "idem" or a Unicode range of the
243              same length */
244           while (*p == ' ' || *p == '\t')
245             p++;
246           if (!strncmp(p, "idem", 4))
247             {
248               for (i=fp0; i<=fp1; i++)
249                 addpair(i,i);
250               p += 4;
251             }
252           else
253             {
254               un0 = getunicode(&p);
255               while (*p == ' ' || *p == '\t')
256                 p++;
257               if (*p != '-')
258                 {
259                   fprintf(stderr,
260                           _("%s: Corresponding to a range of font positions, "
261                             "there should be a Unicode range\n"),
262                           tblname);
263                   exit(EX_DATAERR);
264                 }
265               p++;
266               un1 = getunicode(&p);
267               if (un0 < 0 || un1 < 0)
268                 {
269                   fprintf(stderr,
270                           _("%s: Bad Unicode range corresponding to font "
271                             "position range 0x%x-0x%x\n"),
272                           tblname, fp0, fp1);
273                   exit(EX_DATAERR);
274                 }
275               if (un1 - un0 != fp1 - fp0)
276                 {
277                   fprintf(stderr,
278                           _("%s: Unicode range U+%x-U+%x not of the same "
279                             "length as font position range 0x%x-0x%x\n"),
280                           tblname, un0, un1, fp0, fp1);
281                   exit(EX_DATAERR);
282                 }
283               for (i=fp0; i<=fp1; i++)
284                 addpair(i, un0-fp0+i);
285             }
286         }
287       else
288         {
289             /* no range; expect a list of unicode values for a single font position */
290
291             while ( (un0 = getunicode(&p)) >= 0 )
292               addpair(fp0, un0);
293         }
294       while (*p == ' ' || *p == '\t')
295         p++;
296       if (*p && *p != '#')
297         fprintf(stderr, _("%s: trailing junk (%s) ignored\n"), tblname, p);
298     }
299
300   /* Okay, we hit EOF, now glyph table should be read */
301
302   fclose(ctbl);
303
304   for ( i = 0 ; i < fontlen ; i++ )
305     {
306       for ( newmbr = unilist[i] ; newmbr ; newmbr = tmpmbr.next )
307         {
308           tmpmbr = *newmbr;
309           unicodepair[0] = (tmpmbr.uc & 0xff);
310           unicodepair[1] = ((tmpmbr.uc >> 8) & 0xff);
311           fwrite(unicodepair, sizeof(unicodepair), 1, out);
312           free(newmbr);
313         }
314
315       /* Write string terminator */
316       unicodepair[0] = (PSF_SEPARATOR & 0xff);
317       unicodepair[1] = ((PSF_SEPARATOR >> 8) & 0xff);
318       fwrite(unicodepair, sizeof(unicodepair), 1, out);
319     }
320
321   fclose(out);
322
323   exit(EX_OK);
324 }