xref: /openbsd/gnu/usr.bin/perl/generate_uudmap.c (revision eac174f2)
1 /* generate_uudmap.c:
2 
3    Create three .h files, whose names are specified as argv[1..3],
4    but are usually uudmap.h, bitcount.h and mg_data.h.
5 
6    It uses mg_raw.h as input, plus it relies on the C compiler knowing
7    the ord value of character literals under EBCDIC, to generate output
8    tables on an order which are platform-specific.
9 
10    The outputs are:
11 
12      uudmap.h:
13          The values which will populate PL_uumap[], as used by
14          unpack('u').
15 
16      bitcount.h
17           The values which will populate PL_bitcount[]:
18           this is a count of bits for each U8 value 0..255.
19           (I'm not sure why this has to be generated - surely it's
20           platform-independent - DAPM.)
21 
22      mg_data.h
23           Takes the input from mg_raw.h and sorts by it magic char;
24           the values will populate PL_magic_data[]: this is an array of
25           per-magic U8 values containing an index into PL_magic_vtables[]
26           plus two flags:
27              PERL_MAGIC_READONLY_ACCEPTABLE
28              PERL_MAGIC_VALUE_MAGIC
29 
30    Originally this program just generated uudmap.h
31    However, when we later wanted to generate bitcount.h, it was easier to
32    refactor it and keep the same name, than either alternative - rename it,
33    or duplicate all of the Makefile logic for a second program.
34    Ditto when mg_data.h was added.
35 */
36 
37 #include <stdio.h>
38 #include <stdlib.h>
39 /* If it turns out that we need to make this conditional on config.sh derived
40    values, it might be easier just to rip out the use of strerrer().  */
41 #include <string.h>
42 /* If a platform doesn't support errno.h, it's probably so strange that
43    "hello world" won't port easily to it.  */
44 #include <errno.h>
45 
46 struct mg_data_raw_t {
47     unsigned char type;
48     const char *value;
49     const char *comment;
50 };
51 
52 static struct mg_data_raw_t mg_data_raw[] = {
53 #ifdef WIN32
54 #  include "..\mg_raw.h"
55 #else
56 #  include "mg_raw.h"
57 #endif
58     {0, 0, 0}
59 };
60 
61 struct mg_data_t {
62     const char *value;
63     const char *comment;
64 };
65 
66 static struct mg_data_t mg_data[256];
67 
68 static void
format_mg_data(FILE * out,const void * thing,size_t count)69 format_mg_data(FILE *out, const void *thing, size_t count) {
70   const struct mg_data_t *p = (const struct mg_data_t *)thing;
71 
72   while (1) {
73       if (p->value) {
74           fprintf(out, "    %s\n    %s", p->comment, p->value);
75       } else {
76           fputs("    0", out);
77       }
78       ++p;
79       if (!--count)
80           break;
81       fputs(",\n", out);
82   }
83   fputc('\n', out);
84 }
85 
86 static void
format_char_block(FILE * out,const void * thing,size_t count)87 format_char_block(FILE *out, const void *thing, size_t count) {
88   const char *block = (const char *)thing;
89 
90   fputs("    ", out);
91   while (count--) {
92     fprintf(out, "%d", *block);
93     block++;
94     if (count) {
95       fputs(", ", out);
96       if (!(count & 15)) {
97         fputs("\n    ", out);
98       }
99     }
100   }
101   fputc('\n', out);
102 }
103 
104 static void
output_to_file(const char * progname,const char * filename,void (format_function)(FILE * out,const void * thing,size_t count),const void * thing,size_t count,const char * header)105 output_to_file(const char *progname, const char *filename,
106                void (format_function)(FILE *out, const void *thing, size_t count),
107                const void *thing, size_t count,
108                const char *header
109 ) {
110   FILE *const out = fopen(filename, "w");
111 
112   if (!out) {
113     fprintf(stderr, "%s: Could not open '%s': %s\n", progname, filename,
114             strerror(errno));
115     exit(1);
116   }
117 
118   fprintf(out, "/* %s:\n", filename);
119   fprintf(out, " * THIS FILE IS AUTO-GENERATED DURING THE BUILD by: %s\n",
120                 progname);
121   fprintf(out, " *\n%s\n*/\n{\n", header);
122   format_function(out, thing, count);
123   fputs("}\n", out);
124 
125   if (fclose(out)) {
126     fprintf(stderr, "%s: Could not close '%s': %s\n", progname, filename,
127             strerror(errno));
128     exit(1);
129   }
130 }
131 
132 
133 static const char PL_uuemap[]
134 = "`!\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_";
135 
136 typedef unsigned char U8;
137 
138 /* This will ensure it is initialized to all zeros.  */
139 static char PL_uudmap[256];
140 static char PL_bitcount[256];
141 
main(int argc,char ** argv)142 int main(int argc, char **argv) {
143   size_t i;
144   int bits;
145   struct mg_data_raw_t *p = mg_data_raw;
146 
147   if (argc < 4 || argv[1][0] == '\0' || argv[2][0] == '\0'
148       || argv[3][0] == '\0') {
149     fprintf(stderr, "Usage: %s uudemap.h bitcount.h mg_data.h\n", argv[0]);
150     return 1;
151   }
152 
153   for (i = 0; i < sizeof(PL_uuemap) - 1; ++i)
154     PL_uudmap[(U8)PL_uuemap[i]] = (char)i;
155   /*
156    * Because ' ' and '`' map to the same value,
157    * we need to decode them both the same.
158    */
159   PL_uudmap[(U8)' '] = 0;
160 
161   output_to_file(argv[0], argv[1], &format_char_block,
162                  (const void *)PL_uudmap, sizeof(PL_uudmap),
163         " * These values will populate PL_uumap[], as used by unpack('u')"
164   );
165 
166   for (bits = 1; bits < 256; bits++) {
167     if (bits & 1)	PL_bitcount[bits]++;
168     if (bits & 2)	PL_bitcount[bits]++;
169     if (bits & 4)	PL_bitcount[bits]++;
170     if (bits & 8)	PL_bitcount[bits]++;
171     if (bits & 16)	PL_bitcount[bits]++;
172     if (bits & 32)	PL_bitcount[bits]++;
173     if (bits & 64)	PL_bitcount[bits]++;
174     if (bits & 128)	PL_bitcount[bits]++;
175   }
176 
177   output_to_file(argv[0], argv[2], &format_char_block,
178                  (const void *)PL_bitcount, sizeof(PL_bitcount),
179      " * These values will populate PL_bitcount[]:\n"
180      " * this is a count of bits for each U8 value 0..255"
181   );
182 
183   while (p->value) {
184       mg_data[p->type].value = p->value;
185       mg_data[p->type].comment = p->comment;
186       ++p;
187   }
188 
189   output_to_file(argv[0], argv[3], &format_mg_data,
190                  (const void *)mg_data, sizeof(mg_data)/sizeof(mg_data[0]),
191      " * These values will populate PL_magic_data[]: this is an array of\n"
192      " * per-magic U8 values containing an index into PL_magic_vtables[]\n"
193      " * plus two flags:\n"
194      " *    PERL_MAGIC_READONLY_ACCEPTABLE\n"
195      " *    PERL_MAGIC_VALUE_MAGIC"
196   );
197 
198   return 0;
199 }
200