From: plonka@carroll1.cc.edu (Dave Plonka)
Newsgroups: comp.lang.c
Subject: Re: Do you know of "switch" for "strings" ?
Date: 16 Apr 92 03:10:15 GMT
Article-I.D.: carroll1.3107
Distribution: comp.lang.c
Organization: Carroll College-Waukesha, WI

In article <1992Apr11.143339.19989@sci.kun.nl> jc@cs.kun.nl (Jan Christiaan van Winkel) writes:
>In <9358@baird.cs.strath.ac.uk> gor@cs.strath.ac.uk (Gordon Russell) writes:
>

[example deleted]

>>/*     This collection of macros allows the user to set up string based       */
>
>>#define string_switch(str) {char *sQpZtP;int sQpZtQ;sQpZtP=str;for(sQpZtQ=0;sQpZtQ!=1;sQpZtQ=1) {if (0) 
>>#define string_case(str)   sQpZtQ=1;} if ((sQpZtQ==1)||(strcmp(sQpZtP,str)==0)) {0?0
>>#define string_default     ;}if(sQpZtQ==0) {0?0
>>#define end_switch_string  }}
>>---------------------------- End of Macro File --------------------------------
>
>That is just too bad! you should have made a program using the
>technique, and then send it in as your entry for the Most Obfuscated C
>Code Contest. I bet it had good chances, it's a jewel ;-)

While I agree this is a jewel, I made a couple of, what I think are,
useful revisions...
The original set of macros above didn't allow you to have two "cases"
immediately following each other (as in the example below...)
They would generate code somethine like:

   0?0:I=1

which is illegal because the expression on the left of the assignment is
not a modifiable lvalue. (The "?:" operator has higher precedence than 
assignment "=".) Curiously it seemed to work properly improperly on with
SAS/C for AmigaDOS in the original form, however the compiler I use under
HP/UX didn't like it.
I changed string_case() as seen below to "(I=1)" rather than "I=1".
Also, I have seen that some people have a nasty habit of putting braces
around the statements within a case, this doesn't work with these macros,

ie.
   string_switch (something)
   {
      case "1":
         {
            /* do this stuff */
         }
      case "2": etc.

and I don't see any way around it either, (unless you lose the ":" after
the string_case() macro invocations, because you need an rvalue after 
"0?0:" and {} isn't one.)

Here's my revision... I've added the trivial STRING_N_CASE() macro since
I often do not have NULL terminated strings but, rather, know the length.
Also, I've changed the var names for readability. (I don't use caps in
var names so these are safe for me.)


/* From original by gor@cs.strath.ac.uk (Gordon Russell) */

#define STRING_SWITCH(STR) {char *S=STR;int I; for(I=0; !I; I=1) {if (I)
#define STRING_CASE(STR)   (I=1);} if (I || !strcmp(S, STR)) {0?0
#define STRING_N_CASE(STR, LEN) (I=1);} if (I || !strncmp(S, STR, LEN)) {0?0
#define STRING_DEFAULT     0;} {0?0
#define END_STRING_SWITCH  }}

eg.
        STRING_SWITCH(s)
        {
           STRING_N_CASE("20", 2):
           STRING_N_CASE("30", 2):
              puts("20 or 30");
              break;

           STRING_N_CASE("40", 2):
           STRING_DEFAULT:
              puts("40 or something else");

        } END_STRING_SWITCH;

will work properly now.

>JC
>-- 
>___  __  ____________________________________________________________________
>   |/  \   Jan Christiaan van Winkel                     jc@phoibos.cs.kun.nl
>   |       Alternative e-mail addresses: jc@oreo.atcmp.nl and jc@atcmp.nl
>__/ \__/ ____________________________________________________________________


Once again, kudos to the original author.
Dave

-----------------------------------------------------------------------///--
    plonka@carroll1.cc.edu      Dave Plonka        Amiga - 68040 -    ///
    ARS: N9HZF               Software Engineer     "Motorollin'!" \\\///
------------------------------------------------------- - Nic Wilson X/-----
Newsgroups: comp.lang.c