Xref: utzoo comp.unix.wizards:16855 comp.lang.c:19277 Path: utzoo!attcan!uunet!mcvax!ukc!stl!stc!datlog!gis From: gis@datlog.co.uk ( Ian Stewartson ) Newsgroups: comp.unix.wizards,comp.lang.c Subject: Re: Needed: A (Portable) way of setting up the arg stack Keywords: 1/varargs, callg Message-ID: <2048@dlvax2.datlog.co.uk> Date: 9 Jun 89 19:14:39 GMT References: <708@mitisft.Convergent.COM> <32208@apple.Apple.COM> <10354@smoke.BRL.MIL> <11830@bloom-beacon.MIT.EDU> Reply-To: gis@datlog.co.uk ( Ian Stewartson ) Organization: Data Logic Ltd, Queens House, Greenhill Way, Harrow, London. Lines: 75 In article <11830@bloom-beacon.MIT.EDU> scs@adam.pika.mit.edu (Steve Summit) writes: >specific problem, not an operating system specific problem.) A >routine such as va_call MUST be written in assembly language; it >is one of the handful of functions I know of that cannot possibly >be written in C. It seemed to me that the printf and scanf (and in particular the vprintf family) have a similar problem looked at in a mirror. They effectively do what you want in reverse. I noticed that all the printf family use the function _doprnt (possibly not on all systems, but certainly the few that I have access to). Therefore va_call could be implemented in the similar manner. Taking Steve's example code, I hacked it to produce a macro va_access to get the top of the argument stack excluding the count and then modified pf.c to produce the following code: #include #include "varargs2.h" #define va_access(stack) &stack[1] main() { va_stack(stack, 10); va_stack_init(stack); va_push(stack, 12, int); va_push(stack, 3.14, double); va_push(stack, "Hello, world!", char *); _doprnt ("%d %f %s\n", va_access(stack), stdout); printf ("%d %f %s\n", 12, 3.14, "Hello, world!"); } Which generates the strings: 12 3.140000 Hello, world! 12 3.140000 Hello, world! (The last printf to check the results). The declaration of _doprnt is of the form int _doprnt (format, args, iop) char *format; va_list args; FILE *iop; and the arguments are accessed within _doprnt using width = va_arg(args, int); There being no va_start and va_end in the function. Now I realised that _doprnt is a special case on Unix systems and may not exist on other systems MS-DOS (which uses _output in MSC5 with iop as the first parameter) or MPE (HP's proprietary 3000 system) which has an odd stack frame format which includes a count of the number of arguments and flags to indicate if an argument is on the stack. However, from what I remember of the version of C we were using on MPE, the printf family shared common code and varargs definitely existed. So it may be possible to generate portable code, especially if varargs exists on the intended system. I tested the code on our Vax (Sys Vr2) and MS-DOS systems. On a personnel note: Thanks Steve, your include file and usage saved me time I would have wasted using a different method. Regards, Ian Stewartson Data Logic Ltd, Queens House, Greenhill Way, Harrow, Middlesex, HA1 1YR, UK. (Phone) +44 1 863 0383 (Telex) 888103 (Fax) +44 1 861 2010 (Network) gis@datlog.co.uk or ukc!datlog!gis