1 /*
2 psftools: Manipulate console fonts in the .PSF format
3 Copyright (C) 2003 John Elliott
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 */
19 #include "cnvshell.h"
20 #include "psflib.h"
21
22 /* Convert an MDA character ROM to a .PSF font.
23 *
24 * We assume the MDA ROM format, with 256 characters, each one 8x14. The
25 * ninth column is synthesized.
26 */
27
28 static char helpbuf[2048];
29 static int v1 = 0;
30 static int v2 = 0;
31 static PSF_FILE psf;
32
33 /* Program name */
34 char *cnv_progname = "TXT2PSF";
35
36 /* ddash = 1 if option started with a double-dash; else 0 */
37 /* Return NULL if OK, else error string */
cnv_set_option(int ddash,char * variable,char * value)38 char *cnv_set_option(int ddash, char *variable, char *value)
39 {
40 if (!stricmp(variable, "psf1")) { v1 = 1; return NULL; }
41 if (!stricmp(variable, "psf2")) { v2 = 1; return NULL; }
42
43 if (strlen(variable) > 2000) variable[2000] = 0;
44 sprintf(helpbuf, "Unknown option: %s\n", variable);
45 return helpbuf;
46 }
47
48
49 /* Return help string */
cnv_help(void)50 char *cnv_help(void)
51 {
52 sprintf(helpbuf, "Syntax: %s textfile psffile { options }\n\n", cnv_progname);
53 strcat (helpbuf, "Options:\n\n"
54 "--psf1: Save in PSF1 format.\n"
55 "--psf2: Save in PSF2 format.\n");
56
57 return helpbuf;
58 }
59
60 #define ATSTART 0
61 #define INHEADER 1
62 #define INCHAR 2
63 #define INBITMAP 3
64
cnv_execute(FILE * infile,FILE * outfile)65 char *cnv_execute(FILE *infile, FILE *outfile)
66 {
67 int rv, n, x = 0, y = 0;
68 int state = 0;
69 char linebuf[2000];
70 char unibuf[2000];
71 char *c;
72 int version = -1, flags = -1, length = -1, width = -1, height = -1;
73 int nchar = 0;
74 int line = 0, wb = 0, havebitmap = 0;
75 psf_byte *charbits = NULL;
76
77 psf_file_new(&psf);
78 while (fgets(linebuf, sizeof(linebuf), infile))
79 {
80 ++line;
81 /* If a long line, devour the rest of it */
82 if (!strchr(linebuf, '\n'))
83 {
84 do
85 {
86 n = fgetc(infile);
87 }
88 while (n != EOF && n != '\n');
89 }
90 c = strchr(linebuf, '\n'); if (c) *c = 0;
91 c = strstr(linebuf, "//"); if (c) *c = 0;
92
93 if (linebuf[0] == 0) continue;
94 if (linebuf[0] == '%')
95 {
96 if (!strncmp(linebuf + 1, "PSF2", 4) && state == ATSTART)
97 {
98 state = INHEADER;
99 continue;
100 }
101 /* %STOP: Immediately stop parsing */
102 else if (!strncmp(linebuf + 1, "STOP", 4))
103 {
104 break;
105 }
106 else if (state == INHEADER)
107 {
108 if (version == -1) return "Version not set";
109 if (flags == -1) return "Flags not set";
110 if (width == -1) return "Width not set";
111 if (height == -1) return "Height not set";
112 if (length == -1) return "Length not set";
113 if (version > 0) return "Versions greater than 0 are not supported";
114 rv = psf_file_create(&psf, width, height,
115 length, (flags & 1));
116 if (!rv)
117 {
118 charbits = malloc(psf.psf_charlen);
119 if (!charbits) rv = PSF_E_NOMEM;
120 }
121 if (rv) return psf_error_string(rv);
122 state = INCHAR;
123 unibuf[0] = 0;
124 wb = ((width + 7) / 8);
125 }
126 else if (state == INCHAR || state == INBITMAP)
127 {
128 if (version == -1) return "Version not set";
129 if (nchar < psf.psf_length) memcpy
130 (psf.psf_data + nchar * psf.psf_charlen,
131 charbits, psf.psf_charlen);
132 if (unibuf[0])
133 {
134 rv = psf_unicode_from_string(&psf, nchar, unibuf);
135 if (rv)
136 {
137 fprintf(stderr, "Line %d: Failed to decode %s\n", line, unibuf);
138 return psf_error_string(rv);
139 }
140 }
141 havebitmap = 0;
142 state = INCHAR;
143 nchar++;
144 unibuf[0] = 0;
145 }
146 else
147 {
148 fprintf(stderr, "Line %d: Unexpected %% line\n", line);
149 return "Invalid input format";
150 }
151 }
152 else
153 {
154 c = strstr(linebuf, ": ");
155 if (c)
156 {
157 *c = 0;
158 c++;
159 while (*c == ' ') c++;
160 if (state == INHEADER)
161 {
162 if (!strcmp(linebuf, "Version"))
163 version = atol(c);
164 else if (!strcmp(linebuf, "Flags"))
165 flags = atol(c);
166 else if (!strcmp(linebuf, "Width"))
167 width = atol(c);
168 else if (!strcmp(linebuf, "Height"))
169 height = atol(c);
170 else if (!strcmp(linebuf, "Length"))
171 length = atol(c);
172 else
173 {
174 fprintf(stderr, "Line %d: Unknown variable name '%s'\n", line, linebuf);
175 return "Invalid input format";
176 }
177 }
178 else if (state == INCHAR)
179 {
180 if (!strcmp(linebuf, "Unicode"))
181 strcpy(unibuf, c);
182 else if (!strcmp(linebuf, "Bitmap"))
183 {
184 strcpy(linebuf, c);
185 state = INBITMAP;
186 havebitmap = 0;
187 x = y = 0;
188 }
189 else
190 {
191 fprintf(stderr, "Line %d: Unknown variable name '%s'\n", line, linebuf);
192 return "Invalid input format";
193 }
194 }
195 else /* Not INCHAR and not INHEADER */
196 {
197 fprintf(stderr, "Line %d: Unknown variable name '%s'\n", line, linebuf);
198 return "Invalid input format";
199 }
200 if (state != INBITMAP) continue;
201 } /* end if (c) */
202 if (state == INBITMAP)
203 {
204 psf_byte *dest, mask;
205 c = linebuf;
206 while (*c)
207 {
208 if (*c != '-' && *c != '#')
209 {
210 c++;
211 continue;
212 }
213 dest = charbits + (y * wb) + (x/8);
214 mask = 0x80 >> (x & 7);
215 if (*c == '#') *dest |= mask;
216 else *dest &= ~mask;
217 x++;
218 if (x >= psf.psf_width) { x = 0; y++; }
219 if (y >= psf.psf_height)
220 {
221 state = INCHAR;
222 havebitmap = 1;
223 break;
224 }
225 ++c;
226 }
227 continue;
228 }
229 fprintf(stderr, "Line %d: Not a Variable: Value pair\n", line);
230 return "Invalid input format";
231 }
232 }
233 if (state == INCHAR && havebitmap)
234 {
235 if (nchar < psf.psf_length) memcpy(psf.psf_data + nchar *
236 psf.psf_charlen, charbits, psf.psf_charlen);
237 if (unibuf[0])
238 {
239 rv = psf_unicode_from_string(&psf, nchar, unibuf);
240 if (rv) return psf_error_string(rv);
241 }
242 }
243 if (v1) psf_force_v1(&psf);
244 if (v2) psf_force_v2(&psf);
245 rv = psf_file_write(&psf, outfile);
246 psf_file_delete(&psf);
247 if (rv) return psf_error_string(rv);
248 return NULL;
249 }
250
251