1 /*
2     psftools: Manipulate console fonts in the .PSF format
3     Copyright (C) 2005  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 
20 /* Merge one or more PSF files into a CPI file */
21 
22 #include "cnvmulti.h"
23 #include "psflib.h"
24 #include "cpi.h"
25 #include <ctype.h>
26 
27 
28 static char helpbuf[2048];
29 static char msgbuf[1000];
30 static int drfont;
31 static int nt;
32 static int verbose;
33 static int inter = 1;
34 static char device[9] = "EGA     ";
35 
36 
37 /* Program name */
38 char *cnv_progname = "PSFS2CPI";
39 
40 /* ddash = 1 if option started with a double-dash; else 0 */
41 /* Return NULL if OK, else error string */
cnv_set_option(int ddash,char * variable,char * value)42 char *cnv_set_option(int ddash, char *variable, char *value)
43 {
44 	if (!stricmp(variable, "drfont"))
45 	{
46 		drfont = 1;
47 		return NULL;
48 	}
49 	if (!stricmp(variable, "nt"))
50 	{
51 		nt = 1;
52 		return NULL;
53 	}
54 	if (!strcmp(variable, "verbose"))
55 	{
56 		verbose = 1;
57 		return NULL;
58 	}
59 	if (!strcmp(variable, "device"))
60 	{
61 		sprintf(device, "%-8.8s", value);
62 		return NULL;
63 	}
64 	if (!strcmp(variable, "comment"))
65 	{
66 		strncpy(msgbuf, value, sizeof(msgbuf)-1);
67 		msgbuf[sizeof(msgbuf)-1] = 0;
68 		return NULL;
69 	}
70 	if (strlen(variable) > 2000) variable[2000] = 0;
71 	sprintf(helpbuf, "Unknown option: %s\n", variable);
72 	return helpbuf;
73 }
74 
75 
76 /* Return help string */
cnv_help(void)77 char *cnv_help(void)
78     {
79     sprintf(helpbuf, "Builds a .CPI codepage from one or more .PSF fonts\n\n"
80 		     "Syntax: %s +nnn source.psf source.psf +nnn "
81 		            "source.psf ... target.cpi \n\n", cnv_progname);
82     strcat(helpbuf,  "Options are: --device=<device name>\n");
83     strcat(helpbuf,  "             --comment=<comment>\n");
84     strcat(helpbuf,  "             --drfont: DRFONT output format\n");
85     strcat(helpbuf,  "             --nt: FONT.NT output format\n");
86     strcat(helpbuf,  "             --verbose: List each file as it is processed\n");
87     return helpbuf;
88     }
89 
90 
91 /* Do the conversion */
cnv_multi(int nfiles,char ** infiles,FILE * outfile)92 char *cnv_multi(int nfiles, char **infiles, FILE *outfile)
93 {
94         int rv, nf, nchars, nc;
95 	psf_dword mc;
96 	CPI_FILE cpi;
97 	CP_HEAD *cph;
98 	CP_FONT *cpf, *cpf2;
99 	PSF_FILE psf;
100 	long codepage = -1;
101 	PSF_MAPPING *mapping = NULL;
102 	char mapname[20];
103         FILE *fp;
104 
105 	if (drfont && nt) return "Output format can't be both DRFONT and FONT.NT";
106 /* Always create the file as FONT. We will convert to FONT.NT or DRFONT
107  * later if required */
108 	cpi_new(&cpi, CPI_FONT);
109         for (nf = 0; nf < nfiles; nf++)
110         {
111 /* The syntax "+nnn" denotes a codepage number */
112 	 	if (infiles[nf][0] == '+' && isdigit(infiles[nf][1]))
113 		{
114 			char *equals;
115 
116 			if (!sscanf(&infiles[nf][1], "%lu", &codepage))
117 				codepage = -1;
118 
119 /* Doesn't handle 65280 properly in 16-bit DOS
120  * codepage = atoi(&infiles[nf][1]); */
121 			equals = strchr(infiles[nf], '=');
122 			if (equals) strcpy(mapname, equals + 1);
123 			else sprintf(mapname, "CP%ld", codepage);
124 			mapping = psf_find_mapping(mapname);
125 			if (!mapping)
126 			{
127 				fprintf(stderr, "Warning: This program contains"
128 				" no mapping for codepage %ld.\nThe first 256"
129 				" characters of provided PSFs will be used.\n",
130 				codepage);
131 			}
132 			else if (verbose)
133 				fprintf(stderr, "Processing codepage %ld\n",
134 						codepage);
135 			continue;
136 		}
137 		if (codepage < 0)
138 			return "No codepage specified for first PSF file.";
139 		if (verbose)
140 			fprintf(stderr,"Processing file: '%s'\n",
141 					infiles[nf]);
142                 if (!strcmp(infiles[nf], "-")) fp = stdin;
143                 else  fp = fopen(infiles[nf], "rb");
144 
145                 if (!fp)
146 		{
147 			perror(infiles[nf]);
148 			return "Cannot open font file.";
149 		}
150 		psf_file_new(&psf);
151 		rv = psf_file_read(&psf, fp);
152                 if (fp != stdin) fclose(fp);
153 		if (rv != PSF_E_OK) return psf_error_string(rv);
154 /* PSF loaded. Get the codepage & font to load into. */
155 		cph = cpi_add_page(&cpi, (unsigned)codepage);
156 		if (!cph) return "Out of memory adding codepage to file";
157 		for (cpf = cph->fonts; cpf != NULL; cpf = cpf->next)
158 		{
159 			if (cpf->height == psf.psf_height &&
160 			    cpf->width  == psf.psf_width)
161 			{
162 				fprintf(stderr, "Codepage %ld already has a %dx%d font; it will be replaced\n", codepage, cpf->height, cpf->width);
163 				if (cpf->data) free(cpf->data);
164 				cpf->data = NULL;
165 				cpf->fontsize = 0;
166 				break;
167 			}
168 		}
169 		if (cpf == NULL)
170 		{
171 			cpf = malloc(sizeof(CP_FONT));
172 			if (cpf == NULL) return "Out of memory adding font to codepage";
173 			memset(cpf, 0, sizeof(CP_FONT));
174 			if (!cph->fonts) cph->fonts = cpf;
175 			else for (cpf2 = cph->fonts; cpf2 != NULL; cpf2 = cpf2->next)
176 			{
177 				if (cpf2->next == NULL)
178 				{
179 					cpf2->next = cpf;
180 					break;
181 				}
182 			}
183 		}
184 		strcpy(cph->dev_name, device);
185 		cph->dev_type = 1;
186 /* OK. cpf is the data structure for the new font, and it's in the chain */
187 		if (psf.psf_length < 256)
188 		{
189 			fprintf(stderr, "Warning: %s has fewer than 256 characters.\n", infiles[nf]);
190 			nchars = psf.psf_length;
191 		}
192 		else    nchars = 256;
193 		cpf->nchars = nchars;
194 		cpf->height = psf.psf_height;
195 		cpf->width  = psf.psf_width;
196 		if (psf.psf_width > 8)
197 		{
198 			fprintf(stderr, "Warning: %s has a width of %ld\n",
199 					infiles[nf], psf.psf_width);
200 		}
201 		cpf->fontsize = nchars * psf.psf_charlen;
202 		cpf->data = malloc(cpf->fontsize);
203 		if (cpf->data == NULL) return "Out of memory adding bitmap to font";
204 		memset(cpf->data, 0, cpf->fontsize);
205 		if (mapping && !psf_is_unicode(&psf))
206 		{
207 			fprintf(stderr, "Warning: File %s has no "
208 			"Unicode table.\nThe first 256 "
209 			"characters will be used.\n", infiles[nf]);
210 		}
211 		if (mapping && psf_is_unicode(&psf))
212 		{
213 			psf_dword codepoint;
214 
215 			for (nc = 0; nc < 256; nc++)
216 			{
217 				codepoint = mapping->psfm_tokens[nc][0];
218 				if (psf_unicode_lookupmap(&psf,mapping,nc,&mc, &codepoint))
219 				{
220 					/* Not found */
221 					if (!psf_unicode_banned(codepoint)) fprintf(stderr, "Warning: %s has no bitmap for U+%04lx\n", infiles[nf], codepoint);
222 				}
223 				else
224 				{
225 					memcpy(cpf->data + nc * psf.psf_charlen,
226 					  psf.psf_data + mc * psf.psf_charlen,
227 					  psf.psf_charlen);
228 				}
229 			}
230 		}
231 		else	/* No mapping, just grab the font as it is */
232 		{
233 			memcpy(cpf->data, psf.psf_data, cpf->fontsize);
234 		}
235 		psf_file_delete(&psf);
236         }
237 	if (drfont) rv = cpi_crush(&cpi);
238 	else
239 	{
240 		rv = cpi_bloat(&cpi);
241 		if (nt) strcpy(cpi.format, "FONT.NT");
242 	}
243 
244 	if (msgbuf[0])
245 	{
246 		cpi.comment = malloc(strlen(msgbuf));
247 		if (cpi.comment)
248 		{
249 			cpi.comment_len = strlen(msgbuf);
250 			memcpy(cpi.comment, msgbuf, cpi.comment_len);
251 		}
252 		else	rv = CPI_ERR_NOMEM;
253 	}
254 	if (!rv) rv = cpi_savefile(&cpi, outfile, inter);
255 	if (!rv) return NULL;
256         return psf_error_string(rv);
257 }
258 
259