add genfont2 and unifont build-dependency
[vncterm.git] / genfont2.c
1 /*
2
3      Copyright (C) 2017 Proxmox Server Solutions GmbH
4
5      Copyright: vncterm is under GNU GPL, the GNU General Public License.
6
7      This program is free software; you can redistribute it and/or modify
8      it under the terms of the GNU General Public License as published by
9      the Free Software Foundation; version 2 dated June, 1991.
10
11      This program is distributed in the hope that it will be useful,
12      but WITHOUT ANY WARRANTY; without even the implied warranty of
13      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14      GNU General Public License for more details.
15
16      You should have received a copy of the GNU General Public License
17      along with this program; if not, write to the Free Software
18      Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
19      02111-1307, USA.
20
21      Author: Dominik Csapak <d.csapak@proxmox.com>
22
23      This tool converts the unifont.hex file format into
24      a binary format used in vncterm to render glyphs.
25 */
26
27
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <inttypes.h>
31 #include <errno.h>
32 #include <getopt.h>
33
34 #define NUMCODEPOINTS 0xFFFF
35 #define GLYPHLINES 16
36 #define INDEXLENGTH 4
37
38 /* parses strings like 00F0 to the integer */
39 long
40 parsehex(char *val, size_t length)
41 {
42     unsigned int value = 0;
43
44     for (size_t i = 0; i < length; i++) {
45         value *= 16;
46         if (val[i] >= '0' && val[i] <= '9') {
47             value += (val[i] - '0');
48         } else if (val[i] >= 'A' && val[i] <= 'F') {
49             value += (val[i] - 'A' + 10);
50         } else if (val[i] >= 'a' && val[i] <= 'f') {
51             value += (val[i] - 'a' + 10);
52         } else {
53             return -1;
54         }
55     }
56
57     return value;
58 }
59
60 void usage(char **argv) {
61     printf("Usage: %s [OPTION]...\n", argv[0]);
62     printf("Converts font data from hex format into binary format used by vncterm.\n");
63
64     printf("\n");
65     printf("  -o, --output    file for output, if omitted, write to STDOUT\n");
66     printf("  -i, --input     file for input, if omitted read from STDIN\n");
67     printf("  -h, --help      display this help\n");
68
69     printf("\nThe input has to be formatted in the hex format of unifont.\n");
70 }
71
72 int
73 main (int argc, char** argv)
74 {
75     FILE *fd;
76     FILE *outfd;
77     char *line = NULL;
78     char *tmp = NULL;
79     char *fontfile = NULL;
80     char *outfile = NULL;
81     size_t linesize = 0;
82     uint8_t emptyglyph[GLYPHLINES*2] = { 0 };
83     uint8_t glyph[GLYPHLINES*2] = { 0 };
84     int nextcodepoint = 0;
85     int codepoint = 0;
86     int c;
87
88     static struct option long_options[] = {
89         {"help", no_argument, 0, 'h'},
90         {"output", required_argument, 0, 'o'},
91         {"input", required_argument, 0, 'i'},
92         { 0 , 0, 0, 0}
93     };
94     int option_index = 0;
95
96     while((c = getopt_long(argc, argv, "hi:o:", long_options, &option_index)) != -1) {
97         switch (c) {
98             case 'h':
99                 usage(argv);
100                 exit(0);
101                 break;
102             case 'o':
103                 outfile = optarg;
104                 break;
105             case 'i':
106                 fontfile = optarg;
107                 break;
108             default:
109                 usage(argv);
110                 exit(1);
111         }
112     }
113
114     if (fontfile != NULL){
115         fd = fopen(fontfile, "r");
116         if (fd == NULL) {
117             fprintf(stderr, "Error opening '%s'\n", fontfile);
118             perror(NULL);
119             exit(2);
120         }
121     } else {
122         fd = stdin;
123     }
124
125     if (outfile != NULL) {
126         outfd = fopen(outfile, "w");
127         if (outfd == NULL) {
128             fprintf(stderr, "Error opening '%s'\n", outfile);
129             perror(NULL);
130             exit(2);
131         }
132     } else {
133         outfd = stdout;
134     }
135
136
137     while (getline(&line, &linesize, fd) != -1) {
138         codepoint = parsehex(line, INDEXLENGTH);
139         if (codepoint == -1) {
140             fprintf(stderr, "Cannot parse codepoint index: '%s'\n", line);
141             free(line);
142             exit(4);
143         }
144
145         /* fill in missing codepoints with empty glyphs */
146         while (nextcodepoint++ < codepoint) {
147             fwrite(emptyglyph, sizeof(emptyglyph), 1, outfd);
148         }
149
150         tmp = line + INDEXLENGTH + 1;
151         size_t i = 0;
152
153         /* parse until end of line */
154         while (*(tmp+i*2) != '\n' && i < sizeof(glyph)) {
155             int value = parsehex(tmp+i*2, 2);
156
157             if (value == -1) {
158                 fprintf(stderr, "Cannot parse glyph from line: '%s' at position %ld ('%s')\n", line, i*2, tmp+i*2);
159                 free(line);
160                 exit(4);
161             }
162
163             glyph[i++] = (uint8_t)value;
164         }
165
166         /* if we have a 1width glyph, fill the rest with zeroes */
167         while (i < sizeof(glyph)) {
168             glyph[i++] = 0;
169         }
170
171         fwrite(glyph, sizeof(glyph), 1, outfd);
172     }
173
174     if(errno) {
175         perror("Cannot not read line from file");
176     }
177
178     while (nextcodepoint++ <= NUMCODEPOINTS) {
179         fwrite(emptyglyph, sizeof(emptyglyph), 1, outfd);
180     }
181
182     free(line);
183     exit(0);
184 }