1// SPDX-License-Identifier: GPL-2.0-or-later
2/*
3 * conmakehash.c
4 *
5 * Create arrays for initializing the kernel folded tables (using a hash
6 * table turned out to be to limiting...)  Unfortunately we can't simply
7 * preinitialize the tables at compile time since kfree() cannot accept
8 * memory not allocated by kmalloc(), and doing our own memory management
9 * just for this seems like massive overkill.
10 *
11 * Copyright (C) 1995-1997 H. Peter Anvin
12 */
13
14#include <stdio.h>
15#include <stdlib.h>
16#include <sysexits.h>
17#include <string.h>
18#include <ctype.h>
19
20#define MAX_FONTLEN 256
21
22typedef unsigned short unicode;
23
24static void usage(char *argv0)
25{
26  fprintf(stderr, "Usage: \n"
27         "        %s chartable [hashsize] [hashstep] [maxhashlevel]\n", argv0);
28  exit(EX_USAGE);
29}
30
31static int getunicode(char **p0)
32{
33  char *p = *p0;
34
35  while (*p == ' ' || *p == '\t')
36    p++;
37  if (*p != 'U' || p[1] != '+' ||
38      !isxdigit(p[2]) || !isxdigit(p[3]) || !isxdigit(p[4]) ||
39      !isxdigit(p[5]) || isxdigit(p[6]))
40    return -1;
41  *p0 = p+6;
42  return strtol(p+2,0,16);
43}
44
45unicode unitable[MAX_FONTLEN][255];
46				/* Massive overkill, but who cares? */
47int unicount[MAX_FONTLEN];
48
49static void addpair(int fp, int un)
50{
51  int i;
52
53  if ( un <= 0xfffe )
54    {
55      /* Check it isn't a duplicate */
56
57      for ( i = 0 ; i < unicount[fp] ; i++ )
58	if ( unitable[fp][i] == un )
59	  return;
60
61      /* Add to list */
62
63      if ( unicount[fp] > 254 )
64	{
65	  fprintf(stderr, "ERROR: Only 255 unicodes/glyph permitted!\n");
66	  exit(EX_DATAERR);
67	}
68
69      unitable[fp][unicount[fp]] = un;
70      unicount[fp]++;
71    }
72
73  /* otherwise: ignore */
74}
75
76int main(int argc, char *argv[])
77{
78  FILE *ctbl;
79  char *tblname;
80  char buffer[65536];
81  int fontlen;
82  int i, nuni, nent;
83  int fp0, fp1, un0, un1;
84  char *p, *p1;
85
86  if ( argc < 2 || argc > 5 )
87    usage(argv[0]);
88
89  if ( !strcmp(argv[1],"-") )
90    {
91      ctbl = stdin;
92      tblname = "stdin";
93    }
94  else
95    {
96      ctbl = fopen(tblname = argv[1], "r");
97      if ( !ctbl )
98	{
99	  perror(tblname);
100	  exit(EX_NOINPUT);
101	}
102    }
103
104  /* For now we assume the default font is always 256 characters. */
105  fontlen = 256;
106
107  /* Initialize table */
108
109  for ( i = 0 ; i < fontlen ; i++ )
110    unicount[i] = 0;
111
112  /* Now we come to the tricky part.  Parse the input table. */
113
114  while ( fgets(buffer, sizeof(buffer), ctbl) != NULL )
115    {
116      if ( (p = strchr(buffer, '\n')) != NULL )
117	*p = '\0';
118      else
119	fprintf(stderr, "%s: Warning: line too long\n", tblname);
120
121      p = buffer;
122
123/*
124 * Syntax accepted:
125 *	<fontpos>	<unicode> <unicode> ...
126 *	<range>		idem
127 *	<range>		<unicode range>
128 *
129 * where <range> ::= <fontpos>-<fontpos>
130 * and <unicode> ::= U+<h><h><h><h>
131 * and <h> ::= <hexadecimal digit>
132 */
133
134      while (*p == ' ' || *p == '\t')
135	p++;
136      if (!*p || *p == '#')
137	continue;	/* skip comment or blank line */
138
139      fp0 = strtol(p, &p1, 0);
140      if (p1 == p)
141	{
142	  fprintf(stderr, "Bad input line: %s\n", buffer);
143	  exit(EX_DATAERR);
144        }
145      p = p1;
146
147      while (*p == ' ' || *p == '\t')
148	p++;
149      if (*p == '-')
150	{
151	  p++;
152	  fp1 = strtol(p, &p1, 0);
153	  if (p1 == p)
154	    {
155	      fprintf(stderr, "Bad input line: %s\n", buffer);
156	      exit(EX_DATAERR);
157	    }
158	  p = p1;
159        }
160      else
161	fp1 = 0;
162
163      if ( fp0 < 0 || fp0 >= fontlen )
164	{
165	    fprintf(stderr,
166		    "%s: Glyph number (0x%x) larger than font length\n",
167		    tblname, fp0);
168	    exit(EX_DATAERR);
169	}
170      if ( fp1 && (fp1 < fp0 || fp1 >= fontlen) )
171	{
172	    fprintf(stderr,
173		    "%s: Bad end of range (0x%x)\n",
174		    tblname, fp1);
175	    exit(EX_DATAERR);
176	}
177
178      if (fp1)
179	{
180	  /* we have a range; expect the word "idem" or a Unicode range of the
181	     same length */
182	  while (*p == ' ' || *p == '\t')
183	    p++;
184	  if (!strncmp(p, "idem", 4))
185	    {
186	      for (i=fp0; i<=fp1; i++)
187		addpair(i,i);
188	      p += 4;
189	    }
190	  else
191	    {
192	      un0 = getunicode(&p);
193	      while (*p == ' ' || *p == '\t')
194		p++;
195	      if (*p != '-')
196		{
197		  fprintf(stderr,
198"%s: Corresponding to a range of font positions, there should be a Unicode range\n",
199			  tblname);
200		  exit(EX_DATAERR);
201	        }
202	      p++;
203	      un1 = getunicode(&p);
204	      if (un0 < 0 || un1 < 0)
205		{
206		  fprintf(stderr,
207"%s: Bad Unicode range corresponding to font position range 0x%x-0x%x\n",
208			  tblname, fp0, fp1);
209		  exit(EX_DATAERR);
210	        }
211	      if (un1 - un0 != fp1 - fp0)
212		{
213		  fprintf(stderr,
214"%s: Unicode range U+%x-U+%x not of the same length as font position range 0x%x-0x%x\n",
215			  tblname, un0, un1, fp0, fp1);
216		  exit(EX_DATAERR);
217	        }
218	      for(i=fp0; i<=fp1; i++)
219		addpair(i,un0-fp0+i);
220	    }
221        }
222      else
223	{
224	    /* no range; expect a list of unicode values for a single font position */
225
226	    while ( (un0 = getunicode(&p)) >= 0 )
227	      addpair(fp0, un0);
228	}
229      while (*p == ' ' || *p == '\t')
230	p++;
231      if (*p && *p != '#')
232	fprintf(stderr, "%s: trailing junk (%s) ignored\n", tblname, p);
233    }
234
235  /* Okay, we hit EOF, now output hash table */
236
237  fclose(ctbl);
238
239
240  /* Compute total size of Unicode list */
241  nuni = 0;
242  for ( i = 0 ; i < fontlen ; i++ )
243    nuni += unicount[i];
244
245  printf("\
246/*\n\
247 * Do not edit this file; it was automatically generated by\n\
248 *\n\
249 * conmakehash %s > [this file]\n\
250 *\n\
251 */\n\
252\n\
253#include <linux/types.h>\n\
254\n\
255u8 dfont_unicount[%d] = \n\
256{\n\t", argv[1], fontlen);
257
258  for ( i = 0 ; i < fontlen ; i++ )
259    {
260      printf("%3d", unicount[i]);
261      if ( i == fontlen-1 )
262        printf("\n};\n");
263      else if ( i % 8 == 7 )
264        printf(",\n\t");
265      else
266        printf(", ");
267    }
268
269  printf("\nu16 dfont_unitable[%d] = \n{\n\t", nuni);
270
271  fp0 = 0;
272  nent = 0;
273  for ( i = 0 ; i < nuni ; i++ )
274    {
275      while ( nent >= unicount[fp0] )
276	{
277	  fp0++;
278	  nent = 0;
279	}
280      printf("0x%04x", unitable[fp0][nent++]);
281      if ( i == nuni-1 )
282         printf("\n};\n");
283       else if ( i % 8 == 7 )
284         printf(",\n\t");
285       else
286         printf(", ");
287    }
288
289  exit(EX_OK);
290}
291