1#!/usr/bin/perl -w
2# I'm assuming that you're running this on some kind of ASCII system, but
3# it will generate EBCDIC too. (TODO)
4use strict;
5use Encode;
6require './regen/regen_lib.pl';
7
8sub make_text {
9    my ($chrmap, $letter, $unpredictable, $nocsum, $size, $condition) = @_;
10    my $text = "    /* $letter */ $size";
11    $text .= " | PACK_SIZE_UNPREDICTABLE" if $unpredictable;
12    $text .= " | PACK_SIZE_CANNOT_CSUM"   if $nocsum;
13    $text .= ",";
14
15    if ($condition) {
16        $text = "#if $condition
17$text
18#else
19    0,
20#endif";
21    }
22    return $text;
23}
24
25sub make_tables {
26    my %arrays;
27
28    my $chrmap = shift;
29    foreach (@_) {
30        my ($letter, $shriek, $unpredictable, $nocsum, $size, $condition) =
31            /^([A-Za-z])(!?)\t(\S*)\t(\S*)\t([^\t\n]+)(?:\t+(.*))?$/ or
32            die "Can't parse '$_'";
33
34        $size = "sizeof($size)" unless $size =~ s/^=//;
35
36        $arrays{$shriek ? 'shrieking' : 'normal'}{ord $chrmap->{$letter}} =
37            make_text($chrmap, $letter,
38                      $unpredictable, $nocsum, $size, $condition);
39    }
40
41    my $text = "STATIC const packprops_t packprops[512] = {\n";
42    foreach my $arrayname (qw(normal shrieking)) {
43        my $array = $arrays{$arrayname} ||
44            die "No defined entries in $arrayname";
45        $text .= "    /* $arrayname */\n";
46        for my $ch (0..255) {
47            $text .= $array->{$ch} || "    0,";
48            $text .= "\n";
49        }
50    }
51    # Join "0," entries together
52    1 while $text =~ s/\b0,\s*\n\s*0,/0, 0,/g;
53    # But split them up again if the sequence gets too long
54    $text =~ s/((?:\b0, ){15}0,) /$1\n    /g;
55    # Clean up final ,
56    $text =~ s/,$//;
57    $text .= "};";
58    return $text;
59}
60
61my @lines = grep {
62    s/#.*//;
63    /\S/;
64} <DATA>;
65
66my %asciimap  = map {chr $_, chr $_} 0..255;
67
68# Currently, all things generated by this on EBCDIC are alphabetics, whose
69# positions are all the same regardless of code page, so any EBCDIC encoding
70# will work; just choose one
71my %ebcdicmap = map {chr $_, Encode::encode("posix-bc", chr $_)} 0..255;
72
73my $fh = open_new('packsizetables.inc', '>', { by => $0, from => 'its data'});
74
75print $fh <<"EOC";
76#if TYPE_IS_SHRIEKING != 0x100
77   ++++shriek offset should be 256
78#endif
79
80typedef U8 packprops_t;
81#if 'J'-'I' == 1
82/* ASCII */
83@{[make_tables (\%asciimap, @lines)]}
84#else
85/* EBCDIC (or bust) */
86@{[make_tables (\%ebcdicmap, @lines)]}
87#endif
88EOC
89
90read_only_bottom_close_and_rename($fh);
91
92__DATA__
93#Symbol	unpredictable
94#		nocsum	size
95c			char
96C			unsigned char
97W	*		unsigned char
98U	*		char
99s!			short
100s			=SIZE16
101S!			unsigned short
102v			=SIZE16
103n			=SIZE16
104S			=SIZE16
105v!			=SIZE16
106n!			=SIZE16
107i			int
108i!			int
109I			unsigned int
110I!			unsigned int
111j			=IVSIZE
112J			=UVSIZE
113l!			long
114l			=SIZE32
115L!			unsigned long
116V			=SIZE32
117N			=SIZE32
118V!			=SIZE32
119N!			=SIZE32
120L			=SIZE32
121p		*	char *
122w	*	*	char
123q			Quad_t	IVSIZE >= 8
124Q			Uquad_t	IVSIZE >= 8
125f			float
126d			double
127F			=NVSIZE
128D			=LONG_DOUBLESIZE	defined(HAS_LONG_DOUBLE)
129