1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
|
/*
* NAME
* srctohex - convert font from src to hex format
*
* EXAMPLE USAGE
* srctohex -w 12 -h 22 < gallant.src > gallant.hex
*/
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <locale.h>
#include <unistd.h>
#include <wchar.h>
#include <errno.h>
#define PixelWidth 12
#define PixelHeight 22
#define PixelSet L'Y'
#define PixelClear L' '
#define LINE_MAX_WCHAR 1024
#define FULL_BLOCK 0x2588
#define STARTCHAR 1
#define BITMAP 2
#define ENDCHAR 3
void parse_options(int aArgc, char **aArgv);
void usage(int aStatus);
void errx(const char *aFormat, ...);
int parse_startchar(const wchar_t *aLine);
void parse_bitmap(const wchar_t *aLine, int aWidth);
void parse_endchar(const wchar_t *aLine);
int gWidth = PixelWidth;
int gHeight = PixelHeight;
int gLineNr = 0;
unsigned int gCodepoint = 0;
int main(int aArgc, char **aArgv) {
if (!setlocale(LC_CTYPE, "")) {
fprintf(stderr, "Can't set the locale. Check LANG, LC_CTYPE, LC_ALL.\n");
exit(EXIT_FAILURE);
}
int expect = STARTCHAR;
int bitmaps = 0;
int glyphs = 0;
int width = 1;
parse_options(aArgc, aArgv);
printf("# Width: %d\n# Height: %d\n", gWidth, gHeight);
wchar_t wbuf[LINE_MAX_WCHAR];
while (fgetws(wbuf, LINE_MAX_WCHAR, stdin)) {
++gLineNr;
switch (expect) {
case STARTCHAR:
width = parse_startchar(wbuf);
expect = BITMAP;
break;
case BITMAP:
parse_bitmap(wbuf, width);
++bitmaps;
if (bitmaps == gHeight) {
putchar('\n');
expect = ENDCHAR;
}
break;
case ENDCHAR:
parse_endchar(wbuf);
expect = STARTCHAR;
bitmaps = 0;
++glyphs;
break;
default:
break;
}
}
if (expect != STARTCHAR)
errx("line %d, glyph U+%04x: incomplete glyph due to early end-of-file\n", gLineNr, gCodepoint);
fprintf(stderr, "found %d glyphs\n", glyphs);
return EXIT_SUCCESS;
}
// Parse a STARTCHAR directive.
//
int parse_startchar(const wchar_t *aLine) {
if (swscanf(aLine, L"STARTCHAR U+%x", &gCodepoint) == 1) {
printf("%04x:", gCodepoint);
return wcwidth(gCodepoint);
}
errx("line %d: expected 'STARTCHAR U+xxxx', got %ls", gLineNr, aLine);
return 0;
}
// Parse a |BITMAP| directive.
//
void parse_bitmap(const wchar_t *aLine, int aWidth) {
const wchar_t *delim1 = wcschr(aLine, L'|');
if (delim1 == NULL)
errx("line %d: initial delimiter '|' not found in %ls; not enough pixel lines?\n", gLineNr, aLine);
const wchar_t *delim2 = wcschr(delim1 + 1, L'|');
if (delim2 == NULL)
errx("line %d: final delimiter '|' not found in %ls", gLineNr, aLine);
const int bits = (delim2 - delim1) - 1;
if (aWidth == 2) {
if (bits != (2 * gWidth))
errx("line %d, glyph U+%04x: expected %d pixels bewteen || delimiters for double width glyph, found %d\n", gLineNr,
gCodepoint, 2 * gWidth, bits);
}
else {
if (bits != gWidth)
errx("line %d, glyph U+%04x: expected %d pixels bewteen || delimiters for normal width glyph, found %d\n", gLineNr,
gCodepoint, gWidth, bits);
}
int hex = 0;
aLine = delim1 + 1;
for (int i = 0; i < bits; ++i) {
const int rem = i % 4;
if (aLine[i] == FULL_BLOCK)
hex += (8 >> rem);
else {
if (aLine[i] != L' ')
errx("line %d, glyph U+%04x: pixels must be SPACE or FULL BLOCK U+2588 '%lc', found '%lc'\n", gLineNr, gCodepoint,
FULL_BLOCK, aLine[i]);
}
if (rem == 3) {
putchar("0123456789abcdef"[hex]);
hex = 0;
}
}
/* Pad to octet with zero bits, if any. */
const int pad = 8 * ((bits + 7) / 8);
for (int i = bits; i < pad; ++i) {
if (i % 4 == 3) {
putchar("0123456789abcdef"[hex]);
hex = 0;
}
}
}
// Parse an ENDCHAR directive.
//
void parse_endchar(const wchar_t *aLine) {
if (wcscmp(aLine, L"ENDCHAR\n") != 0)
errx("line %d, glyph U+%04x: expected 'ENDCHAR', got %ls", gLineNr, gCodepoint, aLine);
}
// Parse the command line options.
//
void parse_options(int aArgc, char **aArgv) {
int ch;
while ((ch = getopt(aArgc, aArgv, "w:h:")) != -1) {
switch (ch) {
case 'h':
if (sscanf(optarg, "%d", &gHeight) != 1)
errx("can't convert '%s' to height integer\n", optarg);
break;
case 'w':
if (sscanf(optarg, "%d", &gWidth) != 1)
errx("can't convert '%s' to width integer\n", optarg);
break;
default:
usage(EXIT_FAILURE);
}
}
}
// Output usage message and exit with status.
//
void usage(int aStatus) {
fprintf(stderr, "usage: srctohex [options]\n");
fprintf(stderr, "Options [default]:\n");
fprintf(stderr, " -h height height in pixels [%d]\n", PixelHeight);
fprintf(stderr, " -w width width in pixels [%d]\n", PixelWidth);
exit(aStatus);
}
// Print formatted message on stderr and exit.
//
void errx(const char *aFormat, ...) {
va_list ap;
va_start(ap, aFormat);
vfprintf(stderr, aFormat, ap);
va_end(ap);
exit(EXIT_FAILURE);
}
/* vim: set tabstop=4 shiftwidth=4 expandtab fileformat=unix: */
|