Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > C Programming > altering an av_list variable

Reply
Thread Tools

altering an av_list variable

 
 
Punkie
Guest
Posts: n/a
 
      09-14-2007
When having optional function arguments, the extra arguments are accessed
via an av_list structure. While traversing is trivial, changing the value
isnt.

<code>
void my_sprintf (char *dest, size_t size, const char *format, ...)
{
<snip>
va_list argptr;
va_start(argptr, format);
while((pos = strcspn(format,"%")) != max) {
switch(format[pos+1]) {
case 'm':
format[pos+1] = 's';
argval = va_arg(cpy,int);
/* change the argval to a char* */
break;
default:
va_arg(cpy,int);
}
}
sprintf(*dest, const char *format, argptr); /* call the std function */
va_end(argptr);
}
</code>

In this example you see an attempt to make the sprintf function also
recognise the "%m" format. It should retrieve the (int) argument and change
its value.

Is it possible to alter the arguments in the va_list at all? Are there other
tricks to do this without rewriting sprintf completely?
 
Reply With Quote
 
 
 
 
Tor Rustad
Guest
Posts: n/a
 
      09-14-2007
Punkie wrote:

[...]

> Are there other tricks to do this without rewriting sprintf completely?


See

http://www.ijs.si/software/snprintf/


A quick and non-portable way, is getting the length via:

null = fopen("/dev/null", "w"); /* UNIX/Linux*/
null = fopen("NUL", "w"); /* Windows */

and then calling

len = vfprintf(null, format, ap);


Note, vfprintf() return int, not size_t.

--
Tor <torust [at] online [dot] no>
 
Reply With Quote
 
 
 
 
Punkie
Guest
Posts: n/a
 
      09-14-2007
Indeed, a good way to do this without rewriting sprintf is to let *others*
rewrite it. However something i didnt find among them is typechecking.

Any sprintf with the same std formatting can use the attributes to defer
typechecking too. Like:
void my_sprintf (char *dest, size_t size, const char *format, ...)
__attribute__((format(printf, 3, 4)));

Altering the types accepted creates a problem as we cant use the attribute
anymore.
2routes to solve this:
*own sprintf implementation, that also does this checking somehow. hmmm but
how?
*filter the format and va_list. Like in the code I presented earlier,
changing the type or eliminaing the arg from the va_list.

Tor Rustad wrote:

> Punkie wrote:
>
> [...]
>
>> Are there other tricks to do this without rewriting sprintf completely?

>
> See
>
> http://www.ijs.si/software/snprintf/
>
>
> A quick and non-portable way, is getting the length via:
>
> null = fopen("/dev/null", "w"); /* UNIX/Linux*/
> null = fopen("NUL", "w"); /* Windows */
>
> and then calling
>
> len = vfprintf(null, format, ap);
>
>
> Note, vfprintf() return int, not size_t.
>


 
Reply With Quote
 
Kenny McCormack
Guest
Posts: n/a
 
      09-14-2007
In article <QEzGi.105220$(E-Mail Removed)-ops.be>,
Punkie <(E-Mail Removed)> wrote:
>When having optional function arguments, the extra arguments are accessed
>via an av_list structure. While traversing is trivial, changing the value
>isnt.


"av_list" and "va_list" are very different things. The people here will
not talk to you about the former.

 
Reply With Quote
 
Ian Collins
Guest
Posts: n/a
 
      09-14-2007
Punkie wrote:

Please don't top-post.

> Tor Rustad wrote:
>
>> Punkie wrote:
>>
>> [...]
>>
>>> Are there other tricks to do this without rewriting sprintf completely?

>> See
>>
>> http://www.ijs.si/software/snprintf/
>>
>>
>> A quick and non-portable way, is getting the length via:
>>
>> null = fopen("/dev/null", "w"); /* UNIX/Linux*/
>> null = fopen("NUL", "w"); /* Windows */
>>
>> and then calling
>>
>> len = vfprintf(null, format, ap);
>>
>>
>> Note, vfprintf() return int, not size_t.
>>

> Indeed, a good way to do this without rewriting sprintf is to let *others*
> rewrite it. However something i didnt find among them is typechecking.
>
> Any sprintf with the same std formatting can use the attributes to defer
> typechecking too. Like:
> void my_sprintf (char *dest, size_t size, const char *format, ...)
> __attribute__((format(printf, 3, 4)));
>

It should be noted that __attribute__ is a (very handy) gcc extension.

--
Ian Collins.
 
Reply With Quote
 
Chris Torek
Guest
Posts: n/a
 
      09-15-2007
In article <MwCGi.105460$(E-Mail Removed)-ops.be>
Punkie <(E-Mail Removed)> wrote:
>Indeed, a good way to do this without rewriting sprintf is
>to let *others* rewrite it.


Indeed.

>Altering the types accepted creates a problem as we cant
>use the [gcc-specific] attribute anymore.


You cannot use this portably anyway, even if all your format
directives match those for printf, since __attribute__ is a
gcc-specific extension (i.e., it does not work very well, or even
at all, in various other C compilers).

If you have "extra" directives, a la syslog() "%m", you have to
work harder. If your extra directives need to access some of
the va_list's variable arguments, you must in fact "rewrite sprintf".

Consider, for instance, the following actual implementation (for
V9 SPARC, with a fairly old version of GCC):

/*__va_ll must be 8 bytes regardless of -mlong32; this avoids a pedwarn()*/
typedef long __va_ll __attribute__((__mode__(__DI__)));

/*
* Pre-V9, we simply had up to 6 values in %o registers, then the rest
* in memory. The V9 convention is different -- it had to change because
* the registers are wider, and someone took the opportunity to fix the
* brokenness: floating point arguments are passed in via the first 16
* %f registers now. Thus, we now have an "argument descriptor" data
* structure.
*
* (Using "long long" for the ni and nd produces shorter code.)
*/
typedef struct __va_data {
__va_ll __va_ni; /* # integers remaining */
__va_ll *__va_ip; /* integer-reg arguments */
__va_ll __va_nd; /* # doubles remaining */
double *__va_dp; /* floating-reg arguments */
__va_ll *__va_rest; /* additional args, if any */
} va_list[1];

/*
* The __builtin_args_info expressions return the number of "registers"
* (if any) worth of fixed arguments. For integer parameters, this is
* simply the number of (widened) integers; for float, double, and long
* double parameters, it is the number of %f registers used, accounting
* for the fact that "double" parameters are passed in an even/odd pair
* (leaving a gap if necessary -- e.g., "void f(float x,double y,...)"
* uses %f0 and <%f2:%f3> for a total of 4 %f registers).
*
* When we invoke __builtin_saveregs() here, it dumps those registers
* that were *not* used up by fixed parameters, integer registers first,
* then %f registers. The latter always starts with an even register
* (to form a pair), even if there were an odd number of fixed "float"
* arguments.
*/
#define va_start(ap, l) __extension__ ({ \
__va_ll *__va_base = __builtin_saveregs(); \
int __va_nfi = __builtin_args_info(0); \
int __va_nff = __builtin_args_info(1); \
if (__va_nfi > 6) \
__va_nfi = 6; \
if (__va_nff > 16) \
__va_nff = 16; \
(ap)->__va_ip = __va_base; \
(ap)->__va_dp = (double *)(__va_base + __va_nfi) ; \
(ap)->__va_ni = 6 - __va_nfi; \
(ap)->__va_nd = 8 - ((__va_nff + 1) / 2); \
(ap)->__va_rest = (__va_ll *)__builtin_next_arg(l); \
})
#define va_end(ap)

/*
* Locate (get the address of) the next integer register. Used for
* integers and pointers (in particular, for the hidden pointer that
* is used to pass aggregates).
*/
#define __va_aireg(ap) \
((ap)->__va_ni <= 0 ? (ap)->__va_rest++ : \
((ap)->__va_ni--, (ap)->__va_ip++))

/*
* Internally, this macro sets __va_p to point to the first byte of the
* object, whatever it is, then extracts the appropriate object.
*
* "Real" parameters are the hardest, because we may need to skip over
* a %f-pair-gap when extracting a long double. Fortunately, the number
* of doubles remaining is odd iff the corresponding parameter skipped
* a %f register pair.
*
* Integer and aggregate parameters are easy, but since we are locating
* the bytes of the integer in question, we need to account for our
* big-endian offset: an int or unsigned int is in the last four, not
* the first four, bytes of the 8-byte integer register value as stored
* in memory.
*/
#define va_arg(ap, ty) __extension__ ({ \
void *__va_p; \
const int __vaclass = __builtin_classify_type(*(ty *)0); \
if (__vaclass >= __record_type_class) \
__va_p = *(void **)__va_aireg(ap); \
else if (__vaclass == __real_type_class) { \
const int __va_n = (sizeof(*(ty *)0) + 7) / 8; \
if (__va_n > 1 && (ap)->__va_nd & 1) \
(ap)->__va_nd--, (ap)->__va_dp++; \
if (((ap)->__va_nd -= __va_n) >= 0) { \
__va_p = (ap)->__va_dp; \
(ap)->__va_dp += __va_n; \
} else { \
__va_p = (ap)->__va_rest; \
(ap)->__va_rest += __va_n; \
} \
} else { \
/* oddly, we get better code with two statements here */ \
__va_p = __va_aireg(ap); \
__va_p = (char *)__va_p + 8 - sizeof(*(ty *)0); \
} \
*(ty *)__va_p; \
})

Here, substituting or removing a parameter is pretty tricky,
especially if the substitute has a different size and/or type from
the original (e.g., replacing a 4-byte "int" with an 8-byte pointer,
or pointer with floating-point value). You need to know which of
the three regions the parameter to be substituted or removed falls
into, and for substitutions, whether the replacement goes in the
same region or not. This information has been removed (from the
structure to which "ap" points) by the time you have used va_arg()
to extract the original value.

Another implementation is much simpler:

#define va_arg(ap, type) \
((type *)(ap += sizeof(type)))[-1]

(where va_start(ap, last) just sets "ap" to point to the right
place in the [single] stack that this implementation uses). Here
substitutions or deletions are usually just a matter of poking the
right value into place, or doing a memmove(). Finding the right
location is easy; finding the size for memmove() is harder but
not nearly as hard as the V9 SPARC version.

Nothing requires the implementation of va_start, va_arg, and so on
to look like one of the two above, but they are the two common
methods I have seen. (Most or all of the tricky stuff can be, and
in my opinion should be, done internally by the compiler, allowing
the following compiler-specific -- but not machine-specific --
variant of <stdarg.h>:

#define va_start(ap, last) __builtin_va_start(ap)
#define va_arg(ap, ty) __builtin_va_arg(ap, ty)
#define va_end(ap) __builtin_va_end(ap)

For some reason, not too many people seem to agree with me on
this one. )
--
In-Real-Life: Chris Torek, Wind River Systems
Salt Lake City, UT, USA (4039.22'N, 11150.29'W) +1 801 277 2603
email: forget about it http://web.torek.net/torek/index.html
Reading email is like searching for food in the garbage, thanks to spammers.
 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
Who is altering Subject lines to begin with Antw: Merv Cisco 10 02-17-2006 03:03 AM
altering Request.Headers =?Utf-8?B?QWRhbQ==?= ASP .Net 1 05-20-2005 02:50 AM
Altering a Bi-Directional Data Line Daragoth VHDL 4 06-30-2004 09:12 AM
Altering page content prior to rendering page on browser Rob Heckart ASP .Net 6 11-26-2003 12:36 PM
Altering error for HTMLInputFile when limit exceeded Eric Sabine ASP .Net 0 08-25-2003 03:11 PM



Advertisments