Is this bad programming?
Richard A. O'Keefe
ok at goanna.cs.rmit.oz.au
Fri Aug 10 17:57:48 AEST 1990
In article <1910 at tkou02.enet.dec.com>, diamond at tkou02.enet.dec.com (diamond at tkovoa) writes:
> In article <1990Aug8.100614.1223 at resam.dk> andrew at resam.dk (Leif Andrew Rump) writes:
> >char errortext[][40] = {
> > "234567890123456789012345678901234567890",
> >#define FILE_FOOTER_ERROR 1
> > "File footer error",
Instead of all this, suppose you have k separate arrays, k >= 1,
that you want to initialise "in parallel". You want to give names
to the numbers, and a name to the total number.
The obvious method is to construct a miniature language a la Bentley.
Take a data file like this:
#File: mktable.demo
#
EntryCt; int whence; int whither; char *name
Butcher; 1; 2; "Butcher"
Baker; 1; 3; "Baker"
Bellman; 2; 3; "Bellman"
Boojum; 0; 0; NULL
#End: mktable.demo
Here the first non-comment line has the form
<total>; <type 1> <name 1>; ... <type k> <name k>
where <total> is the name that will be #defined to the number of
elements in each array, <name i> is the name of the ith array to
be initialised, and <type i> is the type of its elements.
Subsequent non-comment lines have the form
<record name>; <value 1>; ... <value k>
where <record name> is the name that will be #defined to the
record number, and <value i> is a C expression which is to be
one of the initial values of array <name i>.
We feed this through the following AWK script:
#File: mktable.awk
#
BEGIN { # note that no header nor data seen yet
k = 0 # number of fields required in each record
r = 0 # number of data records processed so far
p = 0 # number of data *values* saved in data[]
}
$0 ~ /^[ \t]*#/ { # ignore comment lines
next
}
k == 0 { # first non-comment line is header
if (NF < 2) {
print "Error in line " NR ": 2 or more names expected"
exit
}
k = NF # number of fields to be in EACH line
for (i = 1; i <= NF; i++) name[i] = $i
next # don't treat this as data!
}
k != 0 { # this must be a data record
if (NF != k) {
print "Error in line " NR ": wrong number of fields"
exit
}
print "#define", $1, r # define the record number
r++ # then save the data away
for (i = 2; i <= NF; i++) data[p++] = $i
}
END { # all records seen
if (k == 0) { # never saw a header
print "Error; no header record present"
exit
}
if (r == 0) { # never saw any data
print "Error; no data records present"
exit
}
# otherwise, data[] is r blocks of (k-1) strings
print "#define", name[1], r
for (i = 2; i <= k; i++) {
print name[i] "[] = {"
for (t = i-2; t < p; t += k-1) print "\t" data[t] ","
print "};"
}
}
#End: mktable.awk
In UNIX it is easy to bolt all this together
awk -F\; -f mktable.awk mktable.demo | cb >tables.c
^field separator ^awk program ^data file ^result
(Note that using ; as the field separator allows spaces in expressions.
If you want "strings" or 'ints' containing ";", use some other character.)
The result is
#define Butcher 0
#define Baker 1
#define Bellman 2
#define Boojum 3
#define EntryCt 4
int whence[] = {
1,
1,
2,
0,
};
int whither[] = {
2,
3,
3,
0,
};
char *name[] = {
"Butcher",
"Baker",
"Bellman",
NULL,
};
In MS-DOS, it's a little harder (you might have to get the MKS awk,
for example). On the other hand, it would be pretty easy to translate
this awk program to C. In any case, just #include the result into your
C program, and Bob's your uncle!
--
Taphonomy begins at death.
More information about the Comp.lang.c
mailing list