1#!/usr/bin/perl -w
2#
3# Generate sudo_defs_table and associated defines
4#
5# Input should be formatted thusly:
6#
7# var_name
8#	TYPE
9#	description (or NULL)
10#	array of struct def_values if TYPE == T_TUPLE
11
12# Deal with optional -o (output) argument
13if ($#ARGV > 0 && $ARGV[0] eq "-o") {
14    shift;
15    $header = $cfile = shift;
16    $header .= '.h';
17    $cfile .= '.c';
18}
19die "usage: $0 [input_file]\n" unless $#ARGV == -1 || $#ARGV == 0;
20
21$infile = $ARGV[0] || "def_data.in";
22if (!defined($header)) {
23    $header = $infile;
24    $header =~ s/(\.in)?$/.h/;
25}
26if (!defined($cfile)) {
27    $cfile = $infile;
28    $cfile =~ s/(\.in)?$/.c/;
29}
30
31open(IN, "<$infile") || die "$0: can't open $infile: $!\n";
32open(HEADER, ">$header") || die "$0: can't open $header: $!\n";
33open(CFILE, ">$cfile") || die "$0: can't open $cfile: $!\n";
34
35$count = 0;
36@tuple_values = ( "never" );
37@records = ();
38while(<IN>) {
39    chomp;
40    s/\s*#.*$//;
41    next if /^\s*$/;
42
43    if (/^\S/) {
44	# Store previous record and begin new one
45	$records[$count++] = [$var, $type, $desc, $values, $callback] if defined($var);
46
47	$var = $_;
48	$type = '';
49	$desc = undef;
50	$values = undef;
51	$callback = undef;
52	$field = 0;
53    } else {
54	$field++;
55	s/^\s+//;
56	s/\s+$//;
57	if ($field == 1) {
58	    # type
59	    $type = $_;
60	} elsif ($field == 2) {
61	    # description
62	    if ($_ eq "NULL") {
63		$desc = "NULL";
64	    } else {
65		# Strip leading and trailing double quote and escape the rest
66		s/^"//;
67		s/"$//;
68		s/"/\\"/g;
69		$desc = "\"$_\"";
70	    }
71	} elsif ($field == 3 || $field == 4) {
72	    if (s/^\*//) {
73		$callback = $_;
74	    } else {
75		die "$0: syntax error near line $.\n" if $type !~ /^T_TUPLE/;
76		$values = [ split ];
77		foreach $v (@$values) {
78		    push(@tuple_values, $v) unless grep(/^$v$/, @tuple_values);
79		}
80	    }
81	} else {
82	    die "$0: syntax error near line $.\n";
83	}
84    }
85}
86$records[$count++] = [$var, $type, $desc, $values, $callback] if defined($var);
87
88# Print out value arrays
89for ($i = 0; $i < $count; $i++) {
90    if (defined($records[$i]->[3])) {
91	die "Values list specified for non-tupple\n" unless
92	    $records[$i]->[1] =~ /^T_TUPLE/;
93	printf CFILE "static struct def_values def_data_%s[] = {\n", $records[$i]->[0];
94	foreach (@{$records[$i]->[3]}) {
95	    print CFILE "    { \"$_\", $_ },\n";
96	}
97	print CFILE "    { NULL, 0 },\n";
98	print CFILE "};\n\n";
99    }
100}
101
102# Print each record
103print CFILE "struct sudo_defs_types sudo_defs_table[] = {\n    {\n";
104for ($i = 0; $i < $count; $i++) {
105    &print_record($records[$i], $i);
106}
107print CFILE "\tNULL, 0, NULL\n    }\n};\n";
108
109# Print out def_tuple
110if (@tuple_values) {
111    print HEADER "\nenum def_tupple {\n";
112    for ($i = 0; $i <= $#tuple_values; $i++) {
113	printf HEADER "\t%s%s\n", $tuple_values[$i],
114	    $i != $#tuple_values ? "," : "";
115    }
116    print HEADER "};\n";
117}
118
119close(IN);
120close(HEADER);
121close(CFILE);
122
123sub print_record {
124    my ($rec, $recnum) = @_;
125    my ($i, $v, $defname);
126    # each variable gets a macro to access its value
127    for ($rec->[1]) {
128	if    (/^T_U?INT/)  { $v = "ival"; }
129	elsif (/^T_STR/)    { $v = "str"; }
130	elsif (/^T_FLAG/)   { $v = "flag"; }
131	elsif (/^T_MODE/)   { $v = "mode"; }
132	elsif (/^T_LIST/)   { $v = "list"; }
133	elsif (/^T_LOGFAC/) { $v = "ival"; }
134	elsif (/^T_LOGPRI/) { $v = "ival"; }
135	elsif (/^T_TUPLE/)  { $v = "tuple"; }
136	elsif (/^T_FLOAT/)  { $v = "fval"; }
137	else { die "$0: unknown defaults type: $_\n"; }
138    }
139    printf HEADER "#define %-23s (sudo_defs_table[$recnum].sd_un.${v})\n",
140	"def_$rec->[0]";
141
142    $defname = "I_" . uc($rec->[0]);
143    printf HEADER "#define %-24s%d", $defname, $recnum;
144    #print HEADER "\t/* $rec->[2] */" if defined($rec->[2]);
145    print HEADER "\n";
146
147    print CFILE "\t\"$rec->[0]\", $rec->[1],\n\t$rec->[2],\n";
148    if (defined($rec->[3])) {
149	printf CFILE "\tdef_data_$rec->[0],\n";
150    } else {
151	printf CFILE "\tNULL,\n";
152    }
153    printf CFILE "\t$rec->[4],\n" if defined($rec->[4]);
154    print CFILE "    }, {\n";
155}
156