1 /*
2     psftools: Manipulate console fonts in the .PSF format
3     Copyright (C) 2005, 2008  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 three PSF files into a character ROM */
21 
22 #include "cnvmulti.h"
23 #include "psflib.h"
24 
25 
26 static char helpbuf[2048];
27 static char msgbuf[1025];
28 static int compaq;
29 static unsigned char rom[8192];
30 
31 /* Program name */
32 char *cnv_progname = "PSFS2MDA";
33 
34 /* ddash = 1 if option started with a double-dash; else 0 */
35 /* Return NULL if OK, else error string */
cnv_set_option(int ddash,char * variable,char * value)36 char *cnv_set_option(int ddash, char *variable, char *value)
37 {
38 	if (!stricmp(variable, "compaq"))
39 	{
40 		compaq = 1;
41 		return NULL;
42 	}
43 	if (!strcmp(variable, "comment"))
44 	{
45 		strncpy(msgbuf, value, sizeof(msgbuf)-1);
46 		msgbuf[sizeof(msgbuf)-1] = 0;
47 		return NULL;
48 	}
49 	if (strlen(variable) > 2000) variable[2000] = 0;
50 	sprintf(helpbuf, "Unknown option: %s\n", variable);
51 	return helpbuf;
52 }
53 
54 
55 /* Return help string */
cnv_help(void)56 char *cnv_help(void)
57     {
58     sprintf(helpbuf, "Builds a CGA/MDA/Compaq CGA character ROM from three "
59 		    "fonts\n\n"
60 		     "Syntax: %s source14.psf source8.psf { source8a.psf } "
61 		     	"target.rom\n\n", cnv_progname);
62     strcat(helpbuf,  "Options are: --compaq   Output in Compaq CGA format\n");
63     strcat(helpbuf,  "             --comment=<comment>\n");
64     return helpbuf;
65     }
66 
transform(PSF_FILE * psf,int y0,int dest,int step,int firstc)67 void transform(PSF_FILE *psf, int y0, int dest, int step, int firstc)
68 {
69 	int n, m, y;
70 	psf_dword offset;
71 	psf_dword bytes_line = (psf->psf_width + 7) / 8;
72 
73 	for (n = 0; n < 256; n++)
74 	{
75 		/* Point at character glyph */
76 		offset = (firstc % psf->psf_length) * psf->psf_charlen;
77 		offset += bytes_line * y0;
78 		y = y0;
79 		/* Copy the left-hand 8x8 chunk */
80 		for (m = 0; m < 8; m++)
81 		{
82 			if (y >= psf->psf_height)
83 				rom[dest + m] = 0;
84 			else	rom[dest + m] = psf->psf_data[offset];
85 			offset += bytes_line;
86 			y++;
87 		}
88 		dest += step;
89 		++firstc;
90 	}
91 }
92 
93 /* Do the conversion */
cnv_multi(int nfiles,char ** infiles,FILE * outfile)94 char *cnv_multi(int nfiles, char **infiles, FILE *outfile)
95 {
96         int rv, nf, nc;
97 	PSF_FILE psf[3];
98         FILE *fp;
99 
100 	if (nfiles != 3 && nfiles != 2)
101 		return "Syntax error: Two or three input files must be supplied";
102 
103         for (nf = 0; nf < nfiles; nf++)
104         {
105 		if (!strcmp(infiles[nf], "-")) fp = stdin;
106                 else  fp = fopen(infiles[nf], "rb");
107 
108                 if (!fp)
109                 {
110                         perror(infiles[nf]);
111                         return "Cannot open font file.";
112                 }
113 
114 		psf_file_new(&psf[nf]);
115 		rv = psf_file_read(&psf[nf], fp);
116                 if (fp != stdin) fclose(fp);
117 		if (rv != PSF_E_OK) return psf_error_string(rv);
118 /* PSF loaded. */
119 	}
120 	if (psf[0].psf_height != 14)
121 		fprintf(stderr, "Warning: %s is not 14 pixels high\n", infiles[0]);
122 	if (psf[1].psf_height != 8)
123 		fprintf(stderr, "Warning: %s is not 8 pixels high\n", infiles[1]);
124 	if (nfiles == 3 && psf[2].psf_height != 8)
125 		fprintf(stderr, "Warning: %s is not 8 pixels high\n", infiles[2]);
126 	/* Now generate the ROM */
127 	memset(rom, 0, sizeof(rom));
128 	if (compaq)
129 	{
130 		transform(&psf[0], 8, 0x0000, 16, 0);
131 		transform(&psf[0], 0, 0x0008, 16, 0);
132 		transform(&psf[1], 0, 0x1000, 16, 0);
133 		if (nfiles == 2)
134 			transform(&psf[1], 0, 0x1008, 16, 256);
135 		else	transform(&psf[2], 0, 0x1008, 16,   0);
136 /* Comment, if any */
137 		for (nc = 0; nc < 1024; nc++)
138 		{
139 			if (msgbuf[nc] == 0) break;
140 			rom[nc * 16 + 6] = msgbuf[nc];
141 		}
142 	}
143 	else
144 	{
145 		transform(&psf[0], 0, 0x0000, 8, 0);
146 		transform(&psf[0], 8, 0x0800, 8, 0);
147 		if (nfiles == 2)
148 			transform(&psf[1], 0, 0x1000, 8, 256);
149 		else	transform(&psf[2], 0, 0x1000, 8, 0);
150 		transform(&psf[1], 0, 0x1800, 8, 0);
151 	}
152 	if (fwrite(rom, 1, sizeof(rom), outfile) < (int)sizeof(rom))
153 	{
154 		return "Error writing output file";
155 	}
156 	for (nf = 0; nf < nfiles; nf++)
157 	{
158 		psf_file_delete(&psf[nf]);
159 	}
160 	return NULL;
161 }
162 
163