[net.lang.c] CTRL

Purtill@MIT-MULTICS.ARPA (Mark Purtill) (05/04/85)

<Fnord>
Re: mod.std.c, various.

#define CTRL(XX) ( ($XX)[0] & '\037') 

works (I think) in ANSI C.  (For those of you who've forgotten, this
replaces 

#define CTRL(XX) 'XX' & '\037'

I.e., it converts CTRL(A) to '\001', CTRL(B) to '\002' and so forth,
possibly even doing CTRL([) et. al.  (Not having a copy of the ANSI
standard, I'm not sure.)

(Nb: I've tried to post this twice to cbosgd!std-c@BERKELEY.ARPA, but it
has disapeared without a trace both times.  Hence, I'm posting it to
INFO-C.)

       Mark
^.-.^  Purtill at MIT-MULTICS.ARPA    **Insert favorite disclaimer here**
(("))  2-032 MIT Cambrige MA 02139

mike@whuxl.UUCP (BALDWIN) (05/05/85)

> #define CTRL(XX) ( ($XX)[0] & '\037') 
>	replaces
> #define CTRL(XX) ('XX' & '\037')

A more reasonable definition without any weirdness would be

#define	CTRL(c)	((c) & '\037')

So you use CTRL('g') instead of CTRL(g).  This way it looks more like
a real function call (rather than passing some nonexistent variable g).

Here's a silly though:  since '\xFC' has been added to ANSI C for hex
characters, how about '\^G' for control characters, ala ICON?  I never
did like the CTRL macro.
						Michael Baldwin
						AT&T Bell Labs
						harpo!whuxl!mike

henry@utzoo.UUCP (Henry Spencer) (05/06/85)

> Here's a silly though:  since '\xFC' has been added to ANSI C for hex
> characters, how about '\^G' for control characters, ala ICON?  I never
> did like the CTRL macro.

As has been said before, the right way to do this is:

	#define	BEL	'\007'

or something along those lines.  The character is "BEL", numbered 7 decimal
in the ASCII code; control-G is just the way you type it on many (but not
necessarily all) terminals.
-- 
				Henry Spencer @ U of Toronto Zoology
				{allegra,ihnp4,linus,decvax}!utzoo!henry

mike@whuxl.UUCP (BALDWIN) (05/08/85)

> > [use '\^X' instead of CTRL(x) or CTRL('x')]
> As has been said before, the right way to do this is:
> 	#define	BEL	'\007'

I was thinking mainly about programs that use curses or otherwise read
characters one at a time and do special things with ctrl chars.  E.g.,

	switch (c) {
	case '\^U':
		/* up code */
	case '\^D':
		/* down code */

Etc.  #define's (other than CTRL) just won't do.  And the #define for
CTRL moves around, so you have to use #ifndef.  Glick.

Also, it is easier to think in terms of ctrl chars rather than their
octal values when dealing with funny terminal sequences.  For instance,
the cursor motion sequence on mime's is ^T row col, and using
printf("\^T%c%c", row, col) is a bit more obvious than
printf("\024%c%c", row, col).
						Michael Baldwin
						AT&T Bell Labs
						harpo!whuxl!mike

Purtill@MIT-MULTICS.ARPA (Mark Purtill) (05/11/85)

<Fnord>
Yes, CTRL('F') beats CTRL(F) any day, but the idea was to replace an
existing macro WITHOUT having to change all of the calls to it.  I
really didn't expect any changes made to the standard to replace this
silliness, but when I noticed that it could be done, I felt I ought to
let everyone know.
       Mark
^.-.^  Purtill at MIT-MULTICS.ARPA    **Insert favorite disclaimer here**
(("))  2-032 MIT Cambrige MA 02139

       Mark
^.-.^  Purtill at MIT-MULTICS.ARPA    **Insert favorite disclaimer here**
(("))  2-032 MIT Cambrige MA 02139

Purtill@MIT-MULTICS.ARPA (Mark Purtill) (05/11/85)

<Fnord>
> >> [use '\^X' instead of CTRL(x) or CTRL('x')]
> > As has been said before, the right way to do this is:
> >         #define   BEL       '\007'

> I was thinking mainly about programs that use curses or otherwise read
> characters one at a time and do special things with ctrl chars.  E.g.,

Actually, that's no problem.  You just say

#define UP_CHAR     '\025'
#define DOWN_CHAR   '\004'
...
    switch( c) {                        
        case UP_CHAR:
            ...
        Case DOWN_CHAR:
            ...
            ...
        }

This is actually BETTER, since you don't have magic numbers in the code.
>                                                        using
>printf("\^T%c%c", row, col) is a bit more obvious than
>printf("\024%c%c", row, col).
This brings up a real problem: if you have a magic CHARACTER, you can't
use it in a STRING.  Under ANSI C, at least you can get by with
#define MAGIC_CHAR '\024'
#define MAGIC_CHAR_STRING "\024"
and then say 
    printf( MAGIC_CHAR_STRING "%c%c", row, col) ;
but that's not really satisfactory.  (It *is* better that
    printf( "%c%c%c", MAGIC_CHAR,...) ;
or
    printf( "\666%c%c",...) ;           
tho.)  How about making a string adjacent to a character constant absorb
said character constant?  Then
    "foo" '\001' => "foo\001", and '\001' "foo" => "\001foo", 
just as in the standard, "foo" "\001" => "foo\001".  Then 
    printf( MAGIC_CHAR "%c%c",...) ;
works like one would like.

       Mark
^.-.^  Purtill at MIT-MULTICS.ARPA    **Insert favorite disclaimer here**
(("))  2-032 MIT Cambrige MA 02139

Purtill@MIT-MULTICS.ARPA (Mark Purtill) (05/17/85)

<Fnord>
I'm suprised no one caught me on this. When I said
>#define CTRL(XX) ( ($XX)[0] & '\037')
I should have said
>#define CTRL(XX) ( (#XX)[0] & '\037')
(ie, the $ should have been a #!!)  Sorry about that...

       Mark
^.-.^  Purtill at MIT-MULTICS.ARPA    **Insert favorite disclaimer here**
(("))  2-032 MIT Cambrige MA 02139

arnold@ucsfcgl.UUCP (Ken Arnold%CGL) (05/22/85)

In article <10747@brl-tgr.ARPA> Purtill@MIT-MULTICS.ARPA (Mark Purtill) writes:
>I'm suprised no one caught me on this. When I said
>>#define CTRL(XX) ( ($XX)[0] & '\037')
>I should have said
>>#define CTRL(XX) ( (#XX)[0] & '\037')
>(ie, the $ should have been a #!!)  Sorry about that...

Unless the compiler is incredibly smart, this won't work in 'case'
statements, which is rather important.  Although "a"[0] is, in fact,
a constant, it is only a constant because it is a constant offset
into a *constant array*, which is a rather unusual beast.  The VAX
pcc doesn't figure this out.  Try this on your compiler and see if it
does:

		switch (i) {
		  case "a"[0]:
			break;
		}

Actually, when you think about it, since strings are writeable, "a"[0]
is NOT a constant, since someone else might modify the string.  It is
an indirection off of a constant location, but it is not a constant.

Face it.  We are going to have to kill ourselves trying to work around
the standard committee's refusal to let C work the way it has been working.
I have made my opinion on this known ad nauseum, I'm sure, so I'll just
leave it alone for now...

		Ken Arnold

gwyn@brl-tgr.ARPA (Doug Gwyn <gwyn>) (05/23/85)

> Face it.  We are going to have to kill ourselves trying to work around
> the standard committee's refusal to let C work the way it has been working.

What "C"?  Using undocumented (indeed, unintended) features present
in one particular implementation is not the same as using C the way
it was defined; programmers who stuck to the rules should not have
problems with the ANSI addition of a more carefully designed way to
achieve substitution "within" strings.  The ANSI approach is designed
to support reasonable implementations other than the Reiser CPP,
including token-based CPPs, several of which exist and cannot readily
be made to support Resierisms.

C != BSD

arnold@ucsfcgl.UUCP (Ken Arnold%CGL) (05/25/85)

In article <10948@brl-tgr.ARPA> gwyn@brl-tgr.ARPA (Doug Gwyn <gwyn>) writes:
>> Face it.  We are going to have to kill ourselves trying to work around
>> the standard committee's refusal to let C work the way it has been working.
>What "C"?  Using undocumented (indeed, unintended) features present
>in one particular implementation is not the same as using C the way
>it was defined; ...
>
>C != BSD

Unintended?  That ain't the way I heard it.  In fact, if Reiser hadn't put
some way to do this in, someone else would have invented it, since it is
so useful.

Undocumented is only moderately correct, but neither hither nor yon.  It
is used this way in every Reiser-based preprocessor, and that means not
just BSD (BSD got it from Bell), but every Bell-derived C implementation
as well, and some other compilers, including some for micros.  So what
should be standardized on; most compilers or a few compilers?  And, if you
think that there are more compilers that DON'T do it Reiser's way (an
interesting idea), you might ask about how many lines of code are written
under Reiser-style vs. non-Reiser.

However, I promised myself I wouldn't get into this debate, so this is
the last net.lang.c will hear from me on this unles someone says something
truly wacko and I can't help myself.

		Ken Arnold

guy@sun.uucp (Guy Harris) (05/25/85)

> The ANSI approach is designed to support reasonable implementations other
> than the Reiser CPP, including token-based CPPs, several of which exist
> and cannot readily be made to support Resierisms.
> 
> C != BSD

(X is a feature of the Reiser "cpp") != (X is a BSDism).  Let's be fair here.

	Guy Harris

ado@elsie.UUCP (Arthur David Olson) (05/28/85)

In regard to

	#define CTRL(XX) ( (#XX)[0] & '\037')

in article <507@ucsfcgl.UUCP>, arnold@ucsfcgl.UUCP (Ken Arnold%CGL) writes:

> . . .Unless the compiler is incredibly smart, this won't work in 'case'
> statements, which is rather important. . .
> Actually, when you think about it, since strings are writeable, "a"[0]
> is NOT a constant, since someone else might modify the string. . .

Although if I understand aright the draft standard treats unadorned doubly-
quoted strings as if they were cast to "const", which means that constructs
like "a"[0] would be constants under the draft standard.

As for me, I still favor the
	#define Ctrl(X) ((X) & '\037')
approach.  Change your source once and be done with it.
--
Ken is a Kenner Corporation trademark.
--
	UUCP: ..decvax!seismo!elsie!ado    ARPA: elsie!ado@seismo.ARPA
	DEC, VAX and Elsie are Digital Equipment and Borden trademarks

henry@utzoo.UUCP (Henry Spencer) (06/02/85)

> ...  And, if you
> think that there are more compilers that DON'T do it Reiser's way (an
> interesting idea), you might ask about how many lines of code are written
> under Reiser-style vs. non-Reiser.

Actually, the correct version of the latter question is to ask how many
lines of code *care* whether they are written under Reiser-style or
non-Reiser, since the vast bulk of the code written under the Bell-derived
Reiser-style compilers doesn't use Reiserisms.
-- 
				Henry Spencer @ U of Toronto Zoology
				{allegra,ihnp4,linus,decvax}!utzoo!henry

ado@elsie.UUCP (Arthur David Olson) (10/21/86)

Sorry if this has gone around before.

With the Reiser cpp, you can (and "/usr/include/sys/tty.h" does)
	#define	CTRL(c)	('c'&037)
so that a line such as
	CTRL(z)
turns into
	('z'&037)

With ANSI cpp, if you keep the define as above and have a line such as
	CTRL(z)
it turns into
	('c'&037)
which isn't what's wanted.

One possibility is to establish a new macro,
	#define Ctrl(c) ((c)&037)
and change all uses such as
	CTRL(z)
into uses such as
	Ctrl('z')

But. . .is there a way to write an ANSI cpp version of
	#define CTRL(c)
that will work like the old Reiser version?  If you know,
please mail me the answer.  Thanks.
--
ANSI may be an ANSI trademark.
--
	UUCP: ..decvax!seismo!elsie!ado   ARPA: elsie!ado@seismo.ARPA
	DEC, VAX, Elsie & Ado are Digital, Borden & Ampex trademarks.

kb5mu@NOSC.ARPA (10/24/86)

>But. . .is there a way to write an ANSI cpp version of
>        #define CTRL(c)

I don't have an ANSI cpp handy (does anybody?), so I can't test
this, but how about using the ANSI invention of # for "string-izing":
        #define CTRL(c) (#c[0] & 037)
This should turn
        CTRL(z)
into
        ("z"[0] & 037)
which would get what you wanted, except that relatively stupid
compilers might allocate storage for the string literal "z".

greg@utcsri.UUCP (Gregory Smith) (10/29/86)

In article <4880@brl-smoke.ARPA> kb5mu@NOSC.ARPA writes:
>>But. . .is there a way to write an ANSI cpp version of
>>        #define CTRL(c)
>
>I don't have an ANSI cpp handy (does anybody?), so I can't test
>this, but how about using the ANSI invention of # for "string-izing":
>        #define CTRL(c) (#c[0] & 037)
>This should turn
>        CTRL(z)
>into
>        ("z"[0] & 037)
>which would get what you wanted, except that relatively stupid
>compilers might allocate storage for the string literal "z".

It's worse than that. "z"[0] is *("z"), and unary * is not allowed
in constant expressions. So ALL compilers would allow storage for "z"
and then generate code to read that storage at run-time.
Of course, ``case CTRL(c):'' wouldn't work either.

You don't expect C compilers to pull constants out of string literals,
do you?
[ I don't have an Ansi draft, so as far as I know there may be a rule
saying that constant expressions may contain string literals indexed by
constants. But I doubt it].

-- 
----------------------------------------------------------------------
Greg Smith     University of Toronto      UUCP: ..utzoo!utcsri!greg

colonel@sunybcs.UUCP (Col. G. L. Sicherman) (10/31/86)

) >But. . .is there a way to write an ANSI cpp version of
) >        #define CTRL(c)
) 
) I don't have an ANSI cpp handy (does anybody?), so I can't test
) this, but how about using the ANSI invention of # for "string-izing":
)         #define CTRL(c) (#c[0] & 037)

Not everybody has it.  What's wrong with this old trick?

	#define Q "
	#define CTRL(z) (Q z "[1]^0100)
-- 
Col. G. L. Sicherman
UU: ...{rocksvax|decvax}!sunybcs!colonel
CS: colonel@buffalo-cs
BI: colonel@sunybcs, csdsiche@sunyabvc

meissner@dg_rtp.UUCP (Michael Meissner) (11/03/86)

In article <4880@brl-smoke.ARPA> kb5mu@NOSC.ARPA writes:
>>But. . .is there a way to write an ANSI cpp version of
>>        #define CTRL(c)
>
>I don't have an ANSI cpp handy (does anybody?), so I can't test
>this, but how about using the ANSI invention of # for "string-izing":
>        #define CTRL(c) (#c[0] & 037)
>This should turn
>        CTRL(z)
>into
>        ("z"[0] & 037)
>which would get what you wanted, except that relatively stupid
>compilers might allocate storage for the string literal "z".

The problem with using string-izing, is that it is not a constant expression,
and can't be used in switch statements.  Many of the places CTRL(x) is
currently used ARE in switch statements.  Another approach would be to use
token pasting, instead of string-izing:

	enum _ctrl_chars {
		_ctrl_a = 1,
		_ctrl_b = 2,
			/* c, d, etc. */
		_ctrl_z = 26,
		_ctrl_A = 1,
		_ctrl_B = 2,
			/* C, D, etc. */
		_ctrl_Z = 26
	};

	#define CTRL(x)		(int)( _ctrl_ ## x)

The problem with the above is that people have also used CTRL([) to
represent the escape character.

	Michael Meissner, Data General
	...mcnc!rti-sel!dg_rtp!meissner

levy@ttrdc.UUCP (Daniel R. Levy) (11/05/86)

In article <666@dg_rtp.UUCP>, meissner@dg_rtp.UUCP (Michael Meissner) writes:
>In article <4880@brl-smoke.ARPA> kb5mu@NOSC.ARPA writes:
>>        #define CTRL(c) (#c[0] & 037)
>>This should turn
>>        CTRL(z)
>>into
>>        ("z"[0] & 037)
>The problem with using string-izing, is that it is not a constant expression,
>and can't be used in switch statements.  Many of the places CTRL(x) is
>currently used ARE in switch statements.  Another approach would be to use
>token pasting, instead of string-izing:
>
>	enum _ctrl_chars {
>		_ctrl_a = 1,
>		...
>		_ctrl_Z = 26
>	};
>	#define CTRL(x)		(int)( _ctrl_ ## x)
>The problem with the above is that people have also used CTRL([) to
>represent the escape character.
>	Michael Meissner, Data General

At this point, I begin to wonder out loud why all the contortions people are
going to just to avoid typing two silly little single quotes when using a
CTRL macro, i.e.:

#define CTRL(x) (x & 037)

	char c;
	switch (c) {
		CTRL('A'):	blah blah blah...; break;
		CTRL('E'):	bleh bleh bleh...; break;
		...

This even lets you have your CTRL('@') for NUL and CTRL('[') for escape, etc.
I contend this is just as useful as anyone else's suggestion and doesn't rely
on any large list of values or fancy-ANSI [:-)] preprocessor either.
-- 
 -------------------------------    Disclaimer:  The views contained herein are
|       dan levy | yvel nad      |  my own and are not at all those of my em-
|         an engihacker @        |  ployer or the administrator of any computer
| at&t computer systems division |  upon which I may hack.
|        skokie, illinois        |
 --------------------------------   Path: ..!{akgua,homxb,ihnp4,ltuxa,mvuxa,
	   go for it!  			allegra,ulysses,vax135}!ttrdc!levy