Re: Jive -> Kernel (International Linux)

cloister bell (cloister@foo.hhhh.org)
Sat, 18 Jan 1997 23:59:57 -0800 (PST)


> inferno:~/temp$ cat posted.c
> #define INTERNATIONAL(x) \PREINTL(x,LANGUAGE)
> #define PREINTL(x,y) \
> #ifndef x##y\
> x##_generic\
> #else\
> x##y\
> #endif
> inferno:~/temp$ cc posted.c
> posted.c:7: `#' operator should be followed by a macro argument name
> posted.c:7: `#' operator should be followed by a macro argument name
> posted.c:7: `#' operator should be followed by a macro argument name
> inferno:~/temp$

> >I'm not sure this would work, but it should if cpp is worth anything :).

yes, well apparantly it isn't. i couldn't get anything cpp based to go
that far. somebody pointed out that the problem with my solution is that
when you define a new language, you have to make definitions for all the
existing strings for your language. they are completely correct. that is
a bummer, especially with that observation that there are nearly 12000
places right now where such strings would have to be defined. however,
there's a perfectly good perl solution; do a one-time pre-processing of
the kernel source to add the necessary definitions. run everything
through this:

#!/usr/bin/perl
$arg1 = $ARGV[0];
while(<STDIN>) {
print $_;
if(m/(\w+)_generic/) {
print "#define $1_${arg1} $1_generic\n";
}
}

like this:

% addlang.pl sanskrit < whatever.c > /tmp/whatever.c; mv /tmp/whatever.c .

anything of the form:

#define STRINGNAME_generic "a string"

causes a new line to be added like this:

#define STRINGNAME_sanskrit STRINGNAME_generic

of course, since doing this will touch tons of files, it would make for
such an ugly patch that perhaps linus is the best one to do that
particular part. then whomever wanted the language can have fun
translating 'till the cows come home...

> hot damn, let's all chuck cpp away shall we? ;)

sometimes it might be nice, indeed. :)

anyway, having thought about this some more in light of other people's
comments, i have to say that i doubt we'll ultimately be happy with
anything less than a run-time system rather than a compile-time one.
yeah, the above cruft would probably work for now, but eventually people
are going to want to switch languages without re-compiling (mostly, i
suspect, to distribute just one kernel on a CD to handle every language
rather than dozens), and are going to want to incorporate these sorts of
features into their user-level programs too.

what i think would be really neat is if we had a system whereby string
resources could be compiled into some sort of file that was linked at
run-time with whatever piece of code needed some strings. then, the piece
of code could determine the target language from an environment variable
or /etc/rc file or wherever. it would make a system call to link in the
file containing the strings, and then all your printf's and printk's just
print the right thing. of course, you still have to get in the habit of
referring to strings using symbols rather than string constants.

> >What was the whole PREINTL2 step for, anyways?
>
> no idea. i didn't write it, cloister bell did. i just pointed out where it
> fell over.

#define INTERNATIONAL(x) PREINTL(x,LANGUAGE)
#define PREINTL2(x,y) PREINTL(x,y)
#define PREINTL(x,y) x##y

the problem is that unless you're careful, you can't get LANGUAGE expanded
into it's defined value the way you want. roughly speaking, cpp does this
when it encounters a use of a macro:

1. collect the tokens which comprise the macro
2. look at any arguments of the macro, and expand them if they are also
defined to be something else and if they are *not* preceeded by # or ##
3. re-scan the result

so LANGUAGE doesn't get expanded into its value when INTERNATIONAL() gets
processed because it isn't an argument. therefore, you need at least one
more step to make LANGUAGE into an actual argument of a macro. that; a
two-macro solution, was what i tried first. but then the # signs got in
the way, forcing me to use a third step.

so to pull off something like this--generate a token on the fly from
#defined components, and then have the token expanded into its value--the
variable components of the token need to be the actual argument of a
macro in the definition of which they are not touching a # sign. bleah.
this is explained, not very clearly, on page 290 in the 2nd edition K&R.
it took me several readings to figure it out why i needed a third stage
and what it had to be.