2 Copyright © 1995-2012, The AROS Development Team. All rights reserved.
12 #include <exec/types.h>
13 #include <utility/hooks.h>
14 #include <proto/utility.h>
15 #include <libraries/locale.h>
16 #include <aros/asmcall.h>
17 #include "locale_intern.h"
19 #include <clib/alib_protos.h>
21 #include <aros/debug.h>
23 typedef QUAD FMTLARGESTTYPE
;
24 typedef UQUAD UFMTLARGESTTYPE
;
26 static const UBYTE hexarray
[] = "0123456789abcdef";
27 static const UBYTE HEXarray
[] = "0123456789ABCDEF";
29 APTR
InternalFormatString(const struct Locale
* locale
,
30 CONST_STRPTR fmtTemplate
, CONST_APTR dataStream
,
31 ULONG
*indexStream
, const struct Hook
* putCharFunc
)
38 #define ARG(x) ((CONST_APTR)((IPTR)dataStream + indexStream[(x) - 1]))
46 return (APTR
)dataStream
;
48 template_pos
= 0; /* Current position in the template string */
49 state
= OUTPUT
; /* current state of parsing */
57 ** A format description starts here?
59 if (fmtTemplate
[template_pos
] == '%')
69 ** Call the hook for this character
71 AROS_UFC3NR(VOID
, putCharFunc
->h_Entry
,
72 AROS_UFCA(const struct Hook
*, putCharFunc
, A0
),
73 AROS_UFCA(const struct Locale
*, locale
, A2
),
74 AROS_UFCA(UBYTE
, fmtTemplate
[template_pos
], A1
));
77 ** End of template string? -> End of this function.
79 if (fmtTemplate
[template_pos
] == '\0')
86 //kprintf("OUTPUT: template_pos: %d\n",template_pos);
92 ** The '%' was found in the template string
96 //kprintf("FOUND_FORMAT: template_pos: %d\n",template_pos);
98 ** Does the user want the '%' to be printed?
100 if (fmtTemplate
[template_pos
] == '%')
102 AROS_UFC3NR(VOID
, putCharFunc
->h_Entry
,
103 AROS_UFCA(const struct Hook
*, putCharFunc
, A0
),
104 AROS_UFCA(const struct Locale
*, locale
, A2
),
105 AROS_UFCA(UBYTE
, fmtTemplate
[template_pos
], A1
));
107 arg_counter
--; //stegerg
113 ** Template format: %[arg_pos$][flags][width][.limit][length]type
115 ** arg_pos specifies the position of the argument in the dataStream
116 ** flags only '-' is allowed
119 ** datasize size of the datatype
120 ** type b,d,D,u,U,x,X,s,c
123 BOOL left
= FALSE
; // no flag was found
130 UFMTLARGESTTYPE tmp
= 0;
131 #define BUFFERSIZE 128
132 UBYTE buf
[BUFFERSIZE
];
139 //kprintf("next char: %c\n",fmtTemplate[template_pos]);
141 if (fmtTemplate
[template_pos
] >= '0' &&
142 fmtTemplate
[template_pos
] <= '9')
144 ULONG old_template_pos
= template_pos
;
146 for (arg_pos
= 0; (fmtTemplate
[template_pos
] >= '0' &&
147 fmtTemplate
[template_pos
] <= '9');
151 arg_pos
* 10 + fmtTemplate
[template_pos
] - '0';
154 if (fmtTemplate
[template_pos
] == '$')
158 arg_pos
= arg_counter
;
159 template_pos
= old_template_pos
;
163 arg_pos
= arg_counter
;
168 if (fmtTemplate
[template_pos
] == '-')
175 ** fill character a '0'?
177 if (fmtTemplate
[template_pos
] == '0')
186 if (fmtTemplate
[template_pos
] >= '0' &&
187 fmtTemplate
[template_pos
] <= '9')
189 for (width
= 0; (fmtTemplate
[template_pos
] >= '0' &&
190 fmtTemplate
[template_pos
] <= '9');
194 width
* 10 + fmtTemplate
[template_pos
] - '0';
201 if (fmtTemplate
[template_pos
] == '.')
205 if (fmtTemplate
[template_pos
] >= '0' &&
206 fmtTemplate
[template_pos
] <= '9')
208 for (limit
= 0; (fmtTemplate
[template_pos
] >= '0' &&
209 fmtTemplate
[template_pos
] <= '9');
213 limit
* 10 + fmtTemplate
[template_pos
] -
222 switch (fmtTemplate
[template_pos
])
225 /* IPTR-sized type, can be mixed with %d, %u or %x */
226 datasize
= sizeof(IPTR
);
230 datasize
= sizeof(UQUAD
);
235 if (fmtTemplate
[template_pos
] == 'l')
237 datasize
= sizeof(UQUAD
);
241 datasize
= sizeof(ULONG
);
245 datasize
= sizeof(UWORD
);
250 ** Print it according to the given type info.
252 switch (fmtTemplate
[template_pos
])
254 case 'b': /* BSTR, see autodocs */
256 ** Important parameters:
257 ** arg_pos, left, buflen, limit
260 BSTR s
= (BSTR
) * (UBYTE
**) ARG(arg_pos
);
262 if (s
!= (BSTR
) BNULL
)
264 buffer
= AROS_BSTR_ADDR(s
);
265 buflen
= AROS_BSTR_strlen(s
);
276 #endif /* !USE_GLOBALLIMIT */
280 case 'd': /* signed decimal */
281 case 'u': /* unsigned decimal */
283 minus
= fmtTemplate
[template_pos
] == 'd';
289 tmp
= *(UQUAD
*) ARG(arg_pos
);
290 //buffer = &buf[16+1];
291 minus
*= (FMTLARGESTTYPE
) tmp
< 0;
296 tmp
= *(ULONG
*) ARG(arg_pos
);
297 //buffer = &buf[8+1];
298 minus
*= (LONG
) tmp
< 0;
304 tmp
= *(UWORD
*) ARG(arg_pos
);
305 //buffer = &buf[4+1];
306 minus
*= (WORD
) tmp
< 0;
312 buffer
= &buf
[BUFFERSIZE
];
315 *--buffer
= (tmp
% 10) + '0';
330 case 'D': /* signed decimal with locale's formatting conventions */
331 case 'U': /* unsigned decimal with locale's formatting conventions */
334 ULONG group_index
= 0;
336 minus
= fmtTemplate
[template_pos
] == 'D';
341 tmp
= *(UQUAD
*) ARG(arg_pos
);
342 minus
*= (FMTLARGESTTYPE
) tmp
< 0;
347 tmp
= *(ULONG
*) ARG(arg_pos
);
348 minus
*= (LONG
) tmp
< 0;
354 tmp
= *(UWORD
*) ARG(arg_pos
);
355 minus
*= (WORD
) tmp
< 0;
361 /* BUFFERSIZE should be big enough to format a string
362 ** according to locale's formatting conventions
364 buffer
= &buf
[BUFFERSIZE
];
367 loc_Grouping
[group_index
] : 255;
371 *--buffer
= (tmp
% 10) + '0';
377 if (groupsize
== 0 && tmp
!= 0)
380 ** Write the separator
384 locale
->loc_GroupSeparator
[group_index
];
387 locale
->loc_Grouping
[group_index
+ 1];
392 ** Supposed to use the previous element
395 locale
->loc_Grouping
[group_index
];
413 case 'p': /* lower case pointer string */
414 case 'P': /* upper case pointer string */
416 width
= sizeof(APTR
) * 2;
417 /* %p is always at least natural pointer size */
418 if (datasize
< sizeof(APTR
))
419 datasize
= sizeof(APTR
);
420 case 'x': /* upper case hexadecimal string */
421 case 'X': /* lower case hexadecimal string */
429 tmp
= *(UQUAD
*) ARG(arg_pos
);
430 //buffer = &buf[16+1];
433 tmp
= *(ULONG
*) ARG(arg_pos
);
434 //buffer = &buf[8+1];
438 tmp
= *(UWORD
*) ARG(arg_pos
);
439 //buffer = &buf[4+1];
443 buffer
= &buf
[BUFFERSIZE
];
445 /* NOTE: x/X is reverse to printf, coz orig RawDoFmt %lx for uppercase. */
446 hexa
= (fmtTemplate
[template_pos
] == 'X' ||
447 fmtTemplate
[template_pos
] ==
448 'p') ? hexarray
: HEXarray
;
451 *--buffer
= hexa
[tmp
& 0x0f];
459 case 's': /* NULL terminated string */
462 buffer
= *(UBYTE
**) ARG(arg_pos
);
465 * RawDoFmt() in original AmigaOS(tm) formats NULL pointers as empty strings,
466 * and not something like "(null)". Some software may rely on this behavior.
467 * %b is handled in similar manner.
471 buflen
= strlen(buffer
);
476 #endif /* !USE_GLOBALLIMIT */
481 case 'c': /* Character */
487 (UBYTE
) * (UQUAD
*) ARG(arg_pos
);
491 (UBYTE
) * (ULONG
*) ARG(arg_pos
);
496 (UBYTE
) * (WORD
*) ARG(arg_pos
);
505 /* Ignore the faulty '%' */
507 buf
[0] = fmtTemplate
[template_pos
];
510 arg_pos
= --arg_counter
;
519 Now everything I need is known:
520 buffer - contains the string to be printed
521 buflen - size of the string
522 fill - the pad character
523 left - is 1 if the string should be left aligned
524 width - is the minimal width of the field
525 limit - maximum number of characters to output from a string, default ~0
531 #endif /* USE_GLOBALLIMIT */
533 /* Print padding if right aligned */
535 for (i
= buflen
; i
< width
; i
++)
536 AROS_UFC3NR(VOID
, putCharFunc
->h_Entry
,
537 AROS_UFCA(const struct Hook
*, putCharFunc
, A0
),
538 AROS_UFCA(const struct Locale
*, locale
, A2
),
539 AROS_UFCA(UBYTE
, fill
, A1
));
541 /* Print body up to buflen */
542 for (i
= 0; i
< buflen
; i
++)
544 AROS_UFC3NR(VOID
, putCharFunc
->h_Entry
,
545 AROS_UFCA(const struct Hook
*, putCharFunc
, A0
),
546 AROS_UFCA(const struct Locale
*, locale
, A2
),
547 AROS_UFCA(UBYTE
, *buffer
++, A1
));
550 /* Pad right if left aligned */
552 for (i
= buflen
; i
< width
; i
++)
553 AROS_UFC3NR(VOID
, putCharFunc
->h_Entry
,
554 AROS_UFCA(const struct Hook
*, putCharFunc
, A0
),
555 AROS_UFCA(const struct Locale
*, locale
, A2
),
556 AROS_UFCA(UBYTE
, fill
, A1
));
561 if (arg_pos
> max_argpos
)
562 max_argpos
= arg_pos
;
570 return (APTR
)ARG(max_argpos
);
573 /*****************************************************************************
576 #include <proto/locale.h>
578 AROS_LH4(APTR
, FormatString
,
581 AROS_LHA(const struct Locale
*, locale
, A0
),
582 AROS_LHA(CONST_STRPTR
, fmtTemplate
, A1
),
583 AROS_LHA(CONST_APTR
, dataStream
, A2
),
584 AROS_LHA(const struct Hook
*, putCharFunc
, A3
),
587 struct LocaleBase
*, LocaleBase
, 11, Locale
)
605 *****************************************************************************/
610 #if defined(__arm__) || defined(__x86_64__)
611 va_list nullarg
= {};
616 /* Generate the indexes for the provided datastream */
617 GetDataStreamFromFormat(fmtTemplate
, nullarg
, NULL
, NULL
, NULL
, &indexSize
);
618 indices
= alloca(indexSize
);
619 GetDataStreamFromFormat(fmtTemplate
, nullarg
, NULL
, NULL
, indices
, &indexSize
);
621 return InternalFormatString(locale
, fmtTemplate
,
622 dataStream
, indices
, putCharFunc
);