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 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 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 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 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