Welcome, Guest. Please login or register.

Author Topic: varargs compatibility probs with PPC Oses./Passing to 2nd function  (Read 3938 times)

Description:

0 Members and 1 Guest are viewing this topic.

Offline Piru

  • \' union select name,pwd--
  • Hero Member
  • *****
  • Join Date: Aug 2002
  • Posts: 6946
    • Show all replies
    • http://www.iki.fi/sintonen/
Re: Passing a function's variable arguments to a 2nd one...?
« on: September 13, 2005, 04:49:29 PM »
@Jose
The problem with what you're doing is that you basically end up duplicating sprintf functionality.

This is how I'd do it:

a) Use RawDoFmt twice. First time just count the total size of the string. Allocate buffer, RawDoFmt again, now poking chars to the buffer.

or

b) Use RawDoFmt with dynamically expanding buffer putchproc. You'll prolly end up with slightly larger buffer than necessary, but there will be just one RawDoFmt call.
 

Offline Piru

  • \' union select name,pwd--
  • Hero Member
  • *****
  • Join Date: Aug 2002
  • Posts: 6946
    • Show all replies
    • http://www.iki.fi/sintonen/
Re: Passing a function's variable arguments to a 2nd one...?
« Reply #1 on: September 15, 2005, 07:03:42 PM »
Basically your CountChrs and CpyChr didn't use correct registers. Another bug was that you used 16-bit format codes %c and %d instead of 32-bit %lc and %ld (remember I warned you about the difference?). Here's the fixed code with MorphOS varargs included (code tested with SAS/C and ppc-morphos-gcc):
Code: [Select]

#include <exec/memory.h>
#include <exec/types.h>
#ifdef __MORPHOS__
#include <exec/rawfmt.h>
#endif

#include <proto/exec.h>

#include <stdio.h>
#include <strings.h>

BOOL AllocAndCpyStr (char *CtrlStr, char **dest, ...);

int main (int argc, char **argv)
{
 char *a = &quot;Error a&quot;;
 char *b = &quot;Error b&quot;;
 char *c = 0;

 /* .. Other function code...*/

 /* Make information strings without having to allocate an array everytime for each */
 /* Suppose both error a and b happened. Allocate string with info without having make */
 /* an array with pointers a and b plus other data we want to put into final string */
 /* Also serves to test AllocAndCpyStr */
 if (AllocAndCpyStr (&quot;%s %lc %s \n Test number is %ld&quot;, &c, a, ' ', b, 44))
   printf (&quot;Sucess, concatenation and allocation result is:\n %s\n&quot;,c);
 else
   printf (&quot;Failed\n&quot;);
 if (c)
   FreeMem (c, strlen (c) + 1);
 return 0;
}

#ifndef __MORPHOS__

static const UWORD CountChrs[] =
{
  0x5293,                 /* addq.l  #1,(a3) */
  0x4E75,                 /* rts */
};

static const UWORD CpyChr[] =
{
  0x16C0,                 /* move.b d0,(a3)+ */
  0x4E75,                 /* rts */
};

#endif

/* printf() like, except it copies resulting string to it's own allocated chunk, whose ptr is put in *dest */
/* uses StrToRawDF */
BOOL AllocAndCpyStr (char *CtrlStr, char **dest, ...)
{
 LONG StringSize = 0;
 BOOL Result = FALSE;

 /* Check total size */
 #ifdef __MORPHOS__
 va_list args;
 va_start(args, dest);
 VNewRawDoFmt (CtrlStr, (APTR) RAWFMTFUNC_COUNT, (STRPTR) &StringSize, args);
 va_end(args);
 #else
 RawDoFmt (CtrlStr, &dest + 1, (void (*)(void))CountChrs, &StringSize);
 #endif

 /* Allocate space 4 strings */
 if (!(*dest = (char *)AllocMem (StringSize, MEMF_ANY | MEMF_CLEAR)))
   { printf (&quot;Out of memory in report!\n&quot;);
     goto END;
   }
 printf (&quot;Allocated space (resulting string size) was %ld bytes\n\n&quot;, StringSize);
 Result = TRUE;

 /* Copy over strings */
 #ifdef __MORPHOS__
 va_start(args, dest);
 VNewRawDoFmt (CtrlStr, (APTR) RAWFMTFUNC_STRING, *dest, args);
 va_end(args);
 #else
 RawDoFmt (CtrlStr, &dest + 1, (void (*)(void))CpyChr, *dest);
 #endif

 END:
 return (Result);
}


Here's an alternative way of handling the varargs problem. This version in fact doesn't use varargs at all but temporary LONG array. This method, while is much more portable, also consumes some more resources, and it's as elegant as true varargs. While a return value from macro is needed, this method is GCC (and compatibles) only.

Code: [Select]

#include
#include

#include

#include
#include

#ifdef __PPC__
BOOL _AllocAndCpyStr (char *CtrlStr, char **dest, LONG *args);
#define AllocAndCpyStr(str,dst,args...) \
  ({LONG __array[] = {0, args}; _AllocAndCpyStr(str, dst, __array+1);})
#else
BOOL AllocAndCpyStr (char *CtrlStr, char **dest, ...);
#endif

int main (int argc, char **argv)
{
 char *a = "Error a";
 char *b = "Error b";
 char *c = 0;

 /* .. Other function code...*/

 /* Make information strings without having to allocate an array everytime for each */
 /* Suppose both error a and b happened. Allocate string with info without having make */
 /* an array with pointers a and b plus other data we want to put into final string */
 /* Also serves to test AllocAndCpyStr */
 if (AllocAndCpyStr ("%s %lc %s \n Test number is %ld", &c, a, ' ', b, 44))
   printf ("Sucess, concatenation and allocation result is:\n %s\n",c);
 else
   printf ("Failed\n");
 if (c)
   FreeMem (c, strlen (c) + 1);
 return 0;
}

static const UWORD CountChrs[] =
{
  0x5293,                 /* addq.l  #1,(a3) */
  0x4E75,                 /* rts */
};

static const UWORD CpyChr[] =
{
  0x16C0,                 /* move.b d0,(a3)+ */
  0x4E75,                 /* rts */
};

/* printf() like, except it copies resulting string to it's own allocated chunk, whose ptr is put in *dest */
/* uses StrToRawDF */
#ifdef __PPC__
BOOL _AllocAndCpyStr (char *CtrlStr, char **dest, LONG *args)
#else
BOOL AllocAndCpyStr (char *CtrlStr, char **dest, ...)
#endif
{
 LONG StringSize = 0;
 BOOL Result = FALSE;

 /* Check total size */
 #ifdef __PPC__
 RawDoFmt (CtrlStr, args, (void (*)(void))CountChrs, &StringSize);
 #else
 RawDoFmt (CtrlStr, &dest + 1, (void (*)(void))CountChrs, &StringSize);
 #endif

 /* Allocate space 4 strings */
 if (!(*dest = (char *)AllocMem (StringSize, MEMF_ANY | MEMF_CLEAR)))
   { printf ("Out of memory in report!\n");
     goto END;
   }
 printf ("Allocated space (resulting string size) was %ld bytes\n\n", StringSize);
 Result = TRUE;

 /* Copy over strings */
 #ifdef __PPC__
 RawDoFmt (CtrlStr, args, (void (*)(void))CpyChr, *dest);
 #else
 RawDoFmt (CtrlStr, &dest + 1, (void (*)(void))CpyChr, *dest);
 #endif

 END:
 return (Result);
}
 

Offline Piru

  • \' union select name,pwd--
  • Hero Member
  • *****
  • Join Date: Aug 2002
  • Posts: 6946
    • Show all replies
    • http://www.iki.fi/sintonen/
Re: Passing a function's variable arguments to a 2nd one...?
« Reply #2 on: September 16, 2005, 05:39:49 PM »
@Jose
Quote
Why? I took care to have them receive the arguments as described in the RawDoFmt docs.

I didn't see that at least...
Code: [Select]

/* Count nr. of times it's called (= string size) */
void CountChrs (char ch, LONG *StringSize)
{ ++*StringSize;
}


void CpyChr (char ch, char *dest)
{ *dest++ = ch;
}

How does that make sure 'ch' is in D0 and 'StringSize'/'dest' in A3?

This is something you'd have to do:
Code: [Select]

/* Count nr. of times it's called (= string size) */
#if defined(__GNUC__) && defined(mc68000)
void CountChrs (char ch __asm("d0"), LONG *StringSize __asm("a3"))
#elif defined(__SASC)
void __asm CountChrs (register __d0 char ch, register __a3 LONG *StringSize)
#else
#error unsupported compiler/cpu combo
#endif
{ ++*StringSize;
}


#if defined(__GNUC__) && defined(mc68000)
void CpyChr (char ch __asm("d0"), char *dest __asm("a3"))
#elif defined(__SASC)
void __asm CpyChr (register __d0 char ch, register __a3 char *dest)
#else
#error unsupported compiler/cpu combo
#endif
{ *dest++ = ch;
}

Now you perhaps understand why I prefer direct UWORD arrays instead of trying to trick the compiler into doing the right thing (tm)...

I tried to explain it in the other thread.

Quote
I'm on 68K so &dest+1 shouldn't be a problem here.

It isn't.