Path: utzoo!utgpu!news-server.csri.toronto.edu!rutgers!usc!samsung!uunet!munnari.oz.au!goanna!ok From: ok@goanna.cs.rmit.oz.au (Richard A. O'Keefe) Newsgroups: comp.lang.c Subject: Re: NULL as a string terminator Message-ID: <3585@goanna.cs.rmit.oz.au> Date: 20 Aug 90 07:39:52 GMT References: <24141@megaron.cs.arizona.edu> <134@blekko.UUCP> <1990Aug20.000227.12867@icc.com> Organization: Comp Sci, RMIT, Melbourne, Australia Lines: 115 In article <1990Aug20.000227.12867@icc.com>, cbp@icc.com (Chris Preston) writes: (quoting a quote) > >Other cases occur where someone makes #defines for error strings > >that are used only once: > >#define FOO_BAR_ERROR "foo bar error" > >#define UNDEF_BAZ_ERR "undef baz err" > > > >I cringe when I come across code like this. Needlessly removing objects > >a level is distracting and gains nothing. and then defends this, where there are conditional definitions. He suggests > #if MSDOS > #define DATACOM_NOT_INIT "Execute datacomm.exe and restart the program" > #elif SYSV > #define DATACOM_NOT_INIT "Contact you system administrator for datacomm startup" > #elif BTOS > #define DATACOM_NOT_INIT "Master Cluster datacomm not initialized" > #else > #define DATACOM_NOT_INIT "Datacomm is not initailized" > #endif as an example of a Good Thing. I cringe when I see code like this too. For why? Internationalisation, _that's_ for why. > It also impacts on the reusability of code. Pay me now or pay me later. Considering the large negative impact on internationalisation of having fixed strings in the program, may we _bill_ him, I wonder? A very simple way of making a "resource file" in UNIX is this: cat >resource.awk <<'end_of_file.' BEGIN { pos = 0 max = 0 } { print "#define", $1, (pos + length($1) + 1) "L" pos += length + 1 # for MS-DOS, use + 2 l = length - length($1) - 1 if (l > max) max = l filename = FILENAME } END { print "#define res__file \"" filename "\"" print "#define res__max " max } end_of_file. cat >resource.c <<'end_of_file.' #include #include "resource.h" char *rescpy(dst, dstlen, offset) char *dst; int dstlen; long offset; { FILE *resfile; char buffer[res__max+1]; int ok; resfile = fopen(res__file, "r"); if (!resfile) return NULL; ok = fseek(resfile, offset, 0) == 0 && fgets(dst, dstlen, resfile) != NULL; fclose(resfile); return ok ? dst : NULL; } void reserr(offset) long offset; { char buffer[512]; if (rescpy(buffer, sizeof buffer, offset)) fprintf(stderr, "%s", buffer); else fprintf(stderr, "Unknown error (%ldL)\n", offset); } end_of_file. This takes a resource file made up of lines If you do awk -f resource.awk resourcefile >resource.h and then cc -c resource.c you get a header file defining the s to be the appropriate offsets in the resource file, and then rescpy(buffer, sizeof buffer, MessageName) with arguments rather like fgets() will give you a copy of the message, and reserr(MessageName) will write the message to stderr. The bottom line is that you can just make a whole bunch of files resource.uk resource.us resource.fr resource.dk and so on, then awk -f resource.awk resource.$LANG >resource.h and re'make'ing your program will let you adapt to a different language. (I used awk here to keep this posting short. It would be better to make the header file with a C program so that you could use ftell() to get exactly the right values to give to fseek().) Of course, if you are using CMS, or VMS, or SVR4, or something with the X/Open "nls" routines, you could use those. Unfortunately, none of these interfaces is portable. A crude and limited hack like the one above may have a (near term) place in writing code portable between these systems. This code is free. Free code is worth what you pay for it. -- The taxonomy of Pleistocene equids is in a state of confusion.