1 /*
2     psftools: Manipulate console fonts in the .PSF format
3     Copyright (C) 2003, 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 #include "cnvshell.h"
20 #include "psflib.h"
21 
22 #define MAX_H 8		/* Maximum font height */
23 
24 #ifndef SEEK_SET	/* Why doesn't Pacific define this? */
25 #define SEEK_SET 0
26 #define SEEK_CUR 1
27 #define SEEK_END 2
28 #endif
29 
30 /* Convert a BBC micro soft-font to a .PSF font.
31  *
32  * We assume a maximum of 256 characters with a maximum height of 8.
33  */
34 static char workbuf[256 * MAX_H];
35 
36 static char helpbuf[2048];
37 static int width  = 8;
38 static int height = 8;
39 static int v1 = 0, v2 = 0;
40 static PSF_MAPPING *codepage = NULL;
41 static PSF_FILE psf;
42 static int firstc = -1;
43 static int lastc = -1;
44 
45 /* Program name */
46 char *cnv_progname = "BBC2PSF";
47 
48 /* ddash = 1 if option started with a double-dash; else 0 */
49 /* Return NULL if OK, else error string */
cnv_set_option(int ddash,char * variable,char * value)50 char *cnv_set_option(int ddash, char *variable, char *value)
51     {
52     if (!stricmp(variable, "width"))  { width  = atoi(value); return NULL; }
53     if (!stricmp(variable, "height")) { height = atoi(value); return NULL; }
54     if (!stricmp(variable, "psf1"))   { v1 = 1; return NULL; }
55     if (!stricmp(variable, "psf2"))   { v2 = 1; return NULL; }
56     if (!stricmp(variable, "codepage"))
57 	{
58 	codepage = psf_find_mapping(value);
59 	if (codepage == NULL) return "Code page name not recognised.";
60 	return NULL;
61 	}
62     if (strlen(variable) > 2000) variable[2000] = 0;
63     sprintf(helpbuf, "Unknown option: %s\n", variable);
64     return helpbuf;
65     }
66 
67 
68 /* Return help string */
cnv_help(void)69 char *cnv_help(void)
70     {
71     sprintf(helpbuf, "Syntax: %s softfont psffile { options }\n\n", cnv_progname);
72     strcat (helpbuf, "Options: \n"
73 	             "    --height=x     Height of glyphs (defaults to 8)\n"
74 	             "    --width=x      Width of glyphs (defaults to 8)\n"
75 	             "    --codepage=x   Create a Unicode directory from the specified code page\n"
76                      "    --psf1         Output in PSF1 format\n"
77                      "    --psf2         Output in PSF2 format (default) \n");
78 
79     return helpbuf;
80     }
81 
82 
cnv_execute(FILE * infile,FILE * outfile)83 char *cnv_execute(FILE *infile, FILE *outfile)
84 {
85 	int rv;
86 	int ch, curchar, y, wb;
87 
88 /* Work through the file until we find VDU23  (redefine character) */
89 
90 	memset(workbuf, 0, sizeof(workbuf));
91 	while (1)
92 	{
93 		ch = fgetc(infile); if (ch == EOF) break;
94 		if (ch != 0x17)	continue; /* VDU23 */
95 
96 		/* Next character says what is being defined. */
97 		ch = fgetc(infile); if (ch == EOF) break;
98 		curchar = ch;
99 		/* The next 8 give the bitmap */
100 		for (y = 0; y < 8; y++)
101 		{
102 			ch = fgetc(infile); if (ch == EOF) break;
103 			workbuf[curchar * 8 + y] = ch;
104 		}
105 		if (ch == EOF) break;
106 /* Character successfully defined. Move on to the next one */
107 		if (curchar < firstc || firstc == -1) firstc = curchar;
108 		if (curchar > lastc  || lastc  == -1) lastc = curchar;
109 	}
110 	if (firstc == -1 || lastc == -1)
111 	{
112 		return "No BBC micro character definitions found in input";
113 	}
114 
115 	psf_file_new(&psf);
116 	rv = psf_file_create(&psf, width, height, lastc - firstc + 1, 0);
117 	if (!rv)
118 	{
119 		wb = psf.psf_charlen / psf.psf_height;
120 		for (ch = firstc; ch <= lastc; ch++)
121 		{
122 			if (ch >= 256) break;
123 
124 			for (y = 0; y < height; y++)
125 			{
126 				if (y >= MAX_H) break;
127 				psf.psf_data[psf.psf_charlen * (ch-firstc)
128 					+ y * wb] = workbuf[ch * MAX_H + y];
129 			}
130 		}
131 
132 		if (codepage)
133 		{
134 			int n;
135 			psf_file_create_unicode(&psf);
136 			for (n = 0; n < lastc - firstc; n++) if (n < 256)
137 				psf_unicode_addmap(&psf, n, codepage, n);
138 		}
139 
140 
141 		if (v1) psf_force_v1(&psf);
142 		if (v2) psf_force_v2(&psf);
143 		rv = psf_file_write(&psf, outfile);
144 	}
145 	psf_file_delete(&psf);
146 	if (rv) return psf_error_string(rv);
147 	return NULL;
148 }
149 
150