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 new PSF file */
21 
22 #include "cnvmulti.h"
23 #include "psflib.h"
24 #include <ctype.h>
25 
26 
27 static char helpbuf[2048];
28 static char msgbuf[1000];
29 static int v1 = 0;
30 static PSF_FILE *psf_in, psf_out;
31 
32 /* Program name */
33 char *cnv_progname = "PSFJOIN";
34 
35 /* ddash = 1 if option started with a double-dash; else 0 */
36 /* Return NULL if OK, else error string */
cnv_set_option(int ddash,char * variable,char * value)37 char *cnv_set_option(int ddash, char *variable, char *value)
38 {
39 	if (!stricmp(variable, "psf1")) { v1 = 1; return NULL; }
40 	if (!stricmp(variable, "psf2")) { v1 = 0; return NULL; }
41 	if (strlen(variable) > 2000) variable[2000] = 0;
42 	sprintf(helpbuf, "Unknown option: %s\n", variable);
43 	return helpbuf;
44 }
45 
46 
47 /* Return help string */
cnv_help(void)48 char *cnv_help(void)
49 {
50     sprintf(helpbuf, "Concatenates .PSF fonts\n\n"
51 		     "Syntax: %s source.psf source.psf "
52 		            " ... target.psf \n\n", cnv_progname);
53     strcat(helpbuf,  "Options are:\n");
54     strcat(helpbuf,  "             --psf1: Output in PSF1 format\n");
55     strcat(helpbuf,  "             --psf2: Output in PSF2 format (default)\n");
56     return helpbuf;
57 }
58 
59 /* Do the conversion */
cnv_multi(int nfiles,char ** infiles,FILE * outfile)60 char *cnv_multi(int nfiles, char **infiles, FILE *outfile)
61 {
62         int rv, nf, nc;
63 	psf_dword mc, nchars, charlen = 0;
64         FILE *fp;
65 	int w = -1, h = -1;
66 	psf_unicode_dirent *ude;
67 
68 /* Load all the source files */
69 	nchars = 0;
70 	psf_in = malloc(nfiles * sizeof(PSF_FILE));
71 	if (!psf_in) return "Out of memory";
72         for (nf = 0; nf < nfiles; nf++)
73         {
74 		psf_file_new(&psf_in[nf]);
75                 if (!strcmp(infiles[nf], "-")) fp = stdin;
76                 else  fp = fopen(infiles[nf], "rb");
77 
78                 if (!fp)
79 		{
80 			perror(infiles[nf]);
81 			return "Cannot open font file.";
82 		}
83 		rv = psf_file_read(&psf_in[nf], fp);
84                 if (fp != stdin) fclose(fp);
85 		if (rv != PSF_E_OK)
86 		{
87 			sprintf(msgbuf, "%s: %s", infiles[nf],
88 					psf_error_string(rv));
89 			return msgbuf;
90 		}
91 		if (w == -1 && h == -1)
92 		{
93 			w = psf_in[nf].psf_width;
94 			h = psf_in[nf].psf_height;
95 			charlen = psf_in[nf].psf_charlen;
96 		}
97 /* Allow a little slackness in the width; we can concatenate say 6x8 and 8x8
98  * fonts */
99 		else if (h != psf_in[nf].psf_height || charlen != psf_in[nf].psf_charlen)
100 		{
101 			return "All fonts must have the same dimensions.";
102 		}
103 		nchars += psf_in[nf].psf_length;
104 	}
105 	rv = psf_file_create(&psf_out, w, h, nchars, 0);
106 	if (rv) return psf_error_string(rv);
107 
108 	mc = 0;
109         for (nf = 0; nf < nfiles; nf++)
110         {
111 		for (nc = 0; nc < psf_in[nf].psf_length; nc++)
112 		{
113 			memcpy(psf_out.psf_data + mc * psf_out.psf_charlen,
114 			       psf_in[nf].psf_data + nc * psf_in[nf].psf_charlen,
115 			       psf_out.psf_charlen);
116 			mc++;
117 		}
118 	}
119 	/* Copy the Unicode directory from the first font only */
120 	rv = 0;
121 	if (psf_is_unicode(&psf_in[0]))
122 	{
123 		rv = psf_file_create_unicode(&psf_out);
124 	}
125 	if (!rv) for (nc = 0; nc < psf_in[0].psf_length; nc++)
126 	{
127 		for (ude = psf_in[0].psf_dirents_used[nc]; ude != NULL; ude = ude->psfu_next)
128 		{
129 			rv = psf_unicode_add(&psf_out, nf, ude->psfu_token);
130 			if (rv) break;
131 		}
132 		if (rv) break;
133 	}
134 	if (!rv) rv = psf_file_write(&psf_out, outfile);
135 	psf_file_delete(&psf_out);
136         for (nf = 0; nf < nfiles; nf++)
137         {
138 		psf_file_delete(&psf_in[nf]);
139 	}
140 	free(psf_in);
141 	if (rv) return psf_error_string(rv);
142 	return NULL;
143 }
144 
145