[net.lang.c] Another printf-type question

LINNDR%VUENGVAX.BITNET@WISCVM.ARPA (07/11/86)

        All this stuff about v*printf has brought me back to a problem
I was trying to solve earlier. Having a terminal that supports inverse
video, blinking and underlining, I thought it would be fun to write some
printing functions to take advantage of these features. For example,

invprintf(fmt,args)
{
        printf(<string to go into inverse video mode>);
        printf(fmt,args);
        printf(<string to leave inverse mode>);
}

This simple solution didn't work. Oh great gurus of such things, what
should I have done?

David Linn
----------------------------------------------------------
ARPANET(?):     LINNDR%VUEngVAX.BITNET@WISCVM.WISC.EDU
BITNET:         LINNDR@VUEngVAX.BITNET
CSNET:          drl@vanderbilt.csnet
Ma Bell:        (615)322-7924
USPS:           P.O. 3241-B Vanderbilt
                Nashville, TN   37235
UUCP:           ...psuvax1!vuengvax.bitnet!linndr

gwyn@brl-smoke.UUCP (07/12/86)

In article <2138@brl-smoke.ARPA> LINNDR%VUENGVAX.BITNET@WISCVM.ARPA writes:
>invprintf(fmt,args)
>{
>        printf(<string to go into inverse video mode>);
>        printf(fmt,args);
>        printf(<string to leave inverse mode>);
>}
>
>This simple solution didn't work. Oh great gurus of such things, what
>should I have done?

Assuming you're using UNIX System V Release 2.0 for sake of concreteness,

#include	<stdio.h>
#include	<varargs.h>

void
invprintf( va_alist )
	va_dcl
	{
	char	*fmt;			/* printf control string */
	va_list	args;			/* argument pointer */

	(void)fputs( "string to enter inverse video mode", stdout );

	va_start( args );

	fmt = va_arg( args, char * );

	(void)vprintf( fmt, args );	/* warning! not printf(va_arg etc. */

	va_end( args );

	(void)fputs( "string to leave inverse video mode", stdout );
	}

The final mechanism of ANSI X3J11 will probably be slightly different.

P.S.  You should perhaps also test whether the write to the terminal succeeds.

rbj%icst-cmr@smoke.UUCP (07/15/86)

> In article <2138@brl-smoke.ARPA> LINNDR%VUENGVAX.BITNET@WISCVM.ARPA writes:
> >invprintf(fmt,args)
> >{
> >        printf(<string to go into inverse video mode>);
> >        printf(fmt,args);
> >        printf(<string to leave inverse mode>);
> >}
> >
> >This simple solution didn't work. Oh great gurus of such things, what
> >should I have done?

The solution presented below is probably correct, given the poster. I
find it rather unreadable, and would opt for a more local but readable
solution. Having expressed my opinions, I present my solutions along with
their required constraints.

First I present Berkeley's solution:

	/* @(#)printf.c	4.1 (Berkeley) 12/21/80 */
	#include	<stdio.h>

	printf(fmt, args)
	char *fmt;
	{
ABC:
		_doprnt(fmt, &args, stdout);
		return(ferror(stdout)? EOF: 0);
XYZ:
	}

The labels ABC & XYZ are where you put the strings to go into reverse
video and back to normal. You also must fix up the return status to
account for the extra I/O.

This only works if all the arguments are pushed on the stack in reverse
order. VAXen, SUNS, most any 68k box, Sequent, most any ns32032 box,
and anyone else attempting to be reasonable.

Secondly, if you are willing to limit

1) the number of parameters to a reasonable number, say ten
2) the type of parameters to only integers and pointers
3) sizeof(int) = sizeof(int *) = sizeof(char *) = sizeof(any *)

then you might like the following solution:

invprintf(fmt,_0,_1,_2,_3,_4,_5,_6,_7,_8,_9)
{	printf(<reverse video>);
	printf(fmt,_0,_1,_2,_3,_4,_5,_6,_7,_8,_9);
	printf(<reverse video>);
}

> Assuming you're using UNIX System V Release 2.0 for sake of concreteness,
> #include	<stdio.h>
> #include	<varargs.h>
> 
> void
> invprintf( va_alist )
> 	va_dcl
> 	{
> 	char	*fmt;			/* printf control string */
> 	va_list	args;			/* argument pointer */
> 
> 	(void)fputs( "string to enter inverse video mode", stdout );
> 
> 	va_start( args );
> 
> 	fmt = va_arg( args, char * );
> 
> 	(void)vprintf( fmt, args );	/* warning! not printf(va_arg etc. */
> 
> 	va_end( args );
> 
> 	(void)fputs( "string to leave inverse video mode", stdout );
> 	}
> 
> The final mechanism of ANSI X3J11 will probably be slightly different.
> 
> P.S.  You should perhaps also test whether the write to the terminal succeeds.
 
	(Root Boy) Jim Cottrell		<rbj@icst-cmr.arpa>
	Are we live or on tape?
.

gwyn@BRL.ARPA (07/15/86)

invprintf(fmt,_0,_1,_2,_3,_4,_5,_6,_7,_8,_9)

is not a portable solution.  In some cases an attempt to invoke
it with a small actual parameter count can even lead to abnormal
process termination.

The reason <varargs.h> or <stdarg.h> exist is to provide the
hooks necessary for implementation of a portable solution;
the other half of the solution requires something like the
v*printf() functions.

The fellow asked the great gurus what he *should* have done.
Why do you feed him that garbage in return?  If it's to show
us that you don't believe in writing portable code, we knew
that already from your ravings about how the VAX is the only
sane architecture.

rbj@icst-cmr.ARPA (07/15/86)

Doug Gwyn chastises me:
	invprintf(fmt,_0,_1,_2,_3,_4,_5,_6,_7,_8,_9)
	
	is not a portable solution. 

I thought I said that. If not, `taint portable', but just might be useful.

	In some cases an attempt to invoke
	it with a small actual parameter count can even lead to abnormal
	process termination.

True, such as floats or doubles, weird format pointers, longs on PDP-11's.
Also, if called directly from main, it could run off the end of the stack.
	
	The reason <varargs.h> or <stdarg.h> exist is to provide the
	hooks necessary for implementation of a portable solution;
	the other half of the solution requires something like the
	v*printf() functions.

I can relate to the v*printf guys.
	
	The fellow asked the great gurus what he *should* have done.
	Why do you feed him that garbage in return? 

For educational purposes. At least my `solutions' are understandable.
The guy was obviously a novice, and while your solution is probably
the best one, do you think he can read it?

Also, there is no harm in disseminating bad information as well as
good, for comparison purposes, so he can tell the difference. Also,
to understand why yours works, it is useful to know the usual
(or original if you will) calling sequence.

Its probably going to be awhile before he ports code all over creation.

I wish *I* had known the magic printf trick when I wrote code that had to
run in both hosted and standalone 68k environments. I wrote three sets of
code, the common stuff, the hosted interface, and the standalone interface.

We were using only integers (chars, shorts, & ints) & pointers. It would
have been easier and more maintainable if I had rewritten a subset of
printf (no floats, no field widths or left justification, etc)
INSTEAD OF AN ENTIRE INCOMPATIBLE EDITING PACKAGE based on Exec 8!!!

	If it's to show us that you don't believe in writing portable
	code, we knew that already from your ravings about how the VAX
	is the only sane architecture.

Why do you keep saying VAX only? I also mentioned 68k's, ns32032's,
I forgot the PDP-11, all of which I would take home to mother.
I suppose even IBM qualifies as a rational data structure.

Just because a piece of hardware exists doesn't mean it's rational.

Just because a piece of hardware is rational doesn't mean the
software model imposed upon it is rational. INTEL's small, medium,
and large models create more problems than they solve. There is
nothing wrong with the 8086 that treating it like a PDP-11 wouldn't cure.

I suppose I would rather program in C than anything else on a
dinosaur, but I would realize that the model was strained at best.

I will never touch one of those beasts again. As far as I am concerned,
they don't exist. If you want to contort your code to conform to the
lowest common denominator, fine. My code is optimized for sanity.

I am from the National Bureau of Standards, and as such, believe
in them. There ain't nothing else but ASCII. My code will never
support EBCDIC. I expect 'I' + 1 to equal 'J'. If it doesn't,
that's your problem. You fix it.

You say your car is 6 volts, positive ground? Wreck it!
There comes a time to forego the past and desanction it.
If you make it easy for them, they'll never give it up.

Okay, I'm ranting again, let me get back to the subject.

It's all a matter of tradeoffs. Portability comes at a price, both
in time and in space (extra characters), which I find detracts
from readability. Yes, I know that one should aim high, and I do.

Perhaps I aim higher than you. You abide the past, I demand the future.

I added proper cautionary notes. I acknowledged your solution.

In any case, yours is not the only opinion. Mine is shared by
others. We are not unaware of the consequences of our actions,
and accept the responsibility for same. We have made our choice.

Respect it. Agree to disagree.

	(Root Boy) Jim Cottrell		<rbj@icst-cmr.arpa>
I guess it was all a DREAM.. or an episode of HAWAII FIVE-O...

throopw@dg_rtp.UUCP (07/17/86)

> rbj@icst-cmr (Root Boy Jim)

> ...
>                 _doprnt(fmt, &args, stdout);
> ...

BEWARE the _doprnt code, my son!
The bits that twitch; the types that clash!
Use the portable varargs stuff,
Avoid the _doprnt's teeth that gnash!
    --- Eric Kiebler (eric@washu.UUCP)
-- 
Wayne Throop      <the-known-world>!mcnc!rti-sel!dg_rtp!throopw

mouse@mcgill-vision.UUCP (der Mouse) (07/22/86)

>> invprintf(fmt,args)
>> {
>>         printf(<string to go into inverse video mode>);
>>         printf(fmt,args);
>>         printf(<string to leave inverse mode>);
>> }
> Assuming you're using UNIX System V Release 2.0 for sake of concreteness,
> [...solution involving....
> 	(void)vprintf( fmt, args );	/* warning! not printf(va_arg etc. */
> ]

Sounds to me more like assuming SVR2 for the sake of  possibility.  Many
Unices  do not have  vprintf(), much though AT&T may wish it  otherwise.
Absent some indication of  what flavor  of UNIX the  solution is desired
for, an "answer"  using  vprintf() not much of an answer.  I doubt  that
the original poster is prepared to change operating systems just  to get
a portable version of invprintf().

By the way, when I need something like this I write it as follows:

/* VARARGS 1 */
invprintf(fmt,a1,a2,a3,a4,a5,a6,a7,a8)
char *fmt;
int a1;
int a2;
int a3;
int a4;
int a5;
int a6;
int a7;
int a8;
{
 printf(<inverse-video-string>);
 printf(fmt,a1,a2,a3,a4,a5,a6,a7,a8);
 printf(<exit-inverse-video-string>);
}

Anyone out there care to enlighten me as to  all the ways  in which this
can fail (besides wanting to print more than eight arguments)?  It works
on enough  machines that I  don't feel *too* guilty using it.   I  would
guess that  it works on  substantially more  machines than the vprintf()
solution.
-- 
					der Mouse

USA: {ihnp4,decvax,akgua,utzoo,etc}!utcsri!mcgill-vision!mouse
     philabs!micomvax!musocs!mcgill-vision!mouse
Europe: mcvax!decvax!utcsri!mcgill-vision!mouse
        mcvax!seismo!cmcl2!philabs!micomvax!musocs!mcgill-vision!mouse
ARPAnet: utcsri!mcgill-vision!mouse@uw-beaver.arpa

"Come with me a few minutes, mortal, and we shall talk."

moss@BRL.ARPA (Gary S. Moss (SLCBR-VLD-V)) (07/28/86)

If you don't have the vprintf() library, but do have a _doprnt(), this may be
a more desirable, non-portable solution than limiting yourself to 8 args...

-moss

#include <stdio.h>
#include <varargs.h>
/* VARARGS */
void
prnt_rvideo( fmt, va_alist )
char	*fmt;
va_dcl
	{	va_list		ap;
	va_start( ap );
	(void) printf( <turn ON standout mode> );
	(void) _doprnt( fmt, ap, stdout );
	(void) printf( <turn OFF standout mode> );
	va_end( ap );
	return;
	}