[comp.windows.x] varargs and X

ken@gatech.edu (Ken Seefried III) (09/07/89)

---

I'm trying to build a general purpose error notification routine
for an X11/Motif application that I am writing.  I need to use
varargs to get the error messages to the routine (printf() style).

There is, however a catch.  I also need to pass the parent widget
ID to this routine.  None of the several FM's that I have give any 
clue as to how I might do this.

More or less, this is what I want to do (sans declarations, etc.):

/*--------------------------------------------------------------------------*/

Widget Error( parent, va_list )

	Widget parent;
        va_dcl

{

va_list         vaargs;
char            *fmt;
unsigned int    foo = 0; 
Arg             xmargs[ 24 ];     
XmString        msgStr_xm;
Widget          error_dialog;
char            buffer[ 1024 ];

        va_start( vaargs );
        fmt = va_arg( args, char * );
        vsscanf( buffer, fmt, vaargs );

        msgStr_xm = XmStringCreate( buffer, CS );

        XtSetArgs( xmargs[ foo ], XmNmessageString, MsgStr_xm ); foo++;

        error_dialog = XmCreateErrorDialog( parent, "Error", xmargs, foo );

	.
	.
	.

/*-------------------------------------------------------------------------*/

Anyone have any insight into the deep dark mysteries of varargs?
Any help would be greatly appreciated...


	...ken seefried iii		...!<anywhere>!gatech!ken
	   ken@gatech.edu

scs@hstbme.mit.edu (Steve Summit) (09/07/89)

In article <19199@gatech.edu> ken@gatech.edu (Ken Seefried III) writes:
>I'm trying to build a general purpose error notification routine
>for an X11/Motif application that I am writing.  I need to use
>varargs to get the error messages to the routine (printf() style).

I assume you want to call this routine with things like

	WidgetError(parentwidget, "funny name \"%s\"", name);

If you are using (old) varargs, I believe that your function's
argument list must contain only the va_alist.  You would have to
pull the widget ID out manually, as you do the printf format:

	WidgetError(va_alist)
	va_dcl
	{
	va_list	vaargs;
	Widget	parent;
	char	*fmt;
	char	buffer[1024];

	va_start(vaargs);
	parent = va_arg(args, Widget);
	fmt = va_arg(args, char *);
	vsprintf(buffer, fmt, vaargs);
	va_end(vaargs);

(Note that I have also removed a space from "Widget Error",
changed va_list in the formal parameters list to va_alist,
changed vsscanf to vsprintf, and added a "call" to va_end.)

The key is that the second argument to va_arg can be any type
descriptor.  (Actually, many implementations are buggy and break
if it's a char, but as long as sizeof(Widget) >= sizeof(int) it
should work.)

It would be worth your while to implement this in terms of the
new ANSI <stdarg.h> instead of the old <varargs.h>.  stdarg
dispenses with va_alist and va_dcl, and allows (nay, requires)
you to have fixed arguments before the variable ones.  The stdarg
implementation would look like this:

	WidgetError(parent, fmt, ...)
	Widget	parent;
	char	*fmt;
	{
	va_list	vaargs;
	char	buffer[1024];

	va_start(vaargs, fmt);
	vsprintf(buffer, fmt, vaargs);
	va_end(vaargs);

Note that, under stdarg, va_start takes the name of the last
fixed parameter as its second argument.

If you don't have an ANSI compiler, you can leave out the ", ..."
in the formals list, and va_start will (can) still work.  If you
don't have <stdarg.h>, I can supply one that should work on
"conventional," stack-based machines.  (I'd append it here, since
it's short, but the machine it's on is down.)

I don't know much about X, but it would be appropriate to provide
an Xwindowvprintf(window, fmt, ...) so that you could printf
things into windows without using the vsprintf/buffer dodge.
(Any fixed-size buffer will always be too big or too small.)
Of course, implementing Xwindowvprintf would be another story.
(From the looks of your example, you're "printing" not to a
window but to an XmString or a "dialog," so a vprintf analogue
would be appropriate for those objects as well.)

                                                Steve Summit

gwyn@smoke.BRL.MIL (Doug Gwyn) (09/07/89)

In article <19199@gatech.edu> ken@gatech.edu (Ken Seefried III) writes:
>Widget Error( parent, va_list )
>	Widget parent;
>        va_dcl
>{
>va_list         vaargs;
>char            *fmt;
>        va_start( vaargs );
>        fmt = va_arg( args, char * );
>        vsscanf( buffer, fmt, vaargs );
>Anyone have any insight into the deep dark mysteries of varargs?

Yes.  There are several problems here.  The first is that correct usage
of varargs requires that the function definition start off like:

Widget Error( va_alist )
	va_dcl
{
va_list		vaargs;
Widget		parent;
char		*fmt;
	va_start( vaargs );
	parent = va_arg( vaargs, Widget );
	fmt = va_arg( vaargs, char * );

Notice several differences, especially the use of va_alist (NOT va_list!).

The second problem is that vsscanf() doesn't normally exist in C libraries.
Therefore you'll have to provide one..