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]))
42 ULONG max_argpos
, max_argpos_datasize
;
46 return (APTR
)dataStream
;
48 template_pos
= 0; /* Current position in the template string */
49 state
= OUTPUT
; /* current state of parsing */
53 max_argpos_datasize
= 0;
58 ** A format description starts here?
60 if (fmtTemplate
[template_pos
] == '%')
70 ** Call the hook for this character
72 AROS_UFC3NR(VOID
, putCharFunc
->h_Entry
,
73 AROS_UFCA(const struct Hook
*, putCharFunc
, A0
),
74 AROS_UFCA(const struct Locale
*, locale
, A2
),
75 AROS_UFCA(UBYTE
, fmtTemplate
[template_pos
], A1
));
78 ** End of template string? -> End of this function.
80 if (fmtTemplate
[template_pos
] == '\0')
87 //kprintf("OUTPUT: template_pos: %d\n",template_pos);
93 ** The '%' was found in the template string
97 //kprintf("FOUND_FORMAT: template_pos: %d\n",template_pos);
99 ** Does the user want the '%' to be printed?
101 if (fmtTemplate
[template_pos
] == '%')
103 AROS_UFC3NR(VOID
, putCharFunc
->h_Entry
,
104 AROS_UFCA(const struct Hook
*, putCharFunc
, A0
),
105 AROS_UFCA(const struct Locale
*, locale
, A2
),
106 AROS_UFCA(UBYTE
, fmtTemplate
[template_pos
], A1
));
108 arg_counter
--; //stegerg
114 ** Template format: %[arg_pos$][flags][width][.limit][length]type
116 ** arg_pos specifies the position of the argument in the dataStream
117 ** flags only '-' is allowed
120 ** datasize size of the datatype
121 ** type b,d,D,u,U,x,X,s,c
124 BOOL left
= FALSE
; // no flag was found
131 UFMTLARGESTTYPE tmp
= 0;
132 #define BUFFERSIZE 128
133 UBYTE buf
[BUFFERSIZE
];
140 //kprintf("next char: %c\n",fmtTemplate[template_pos]);
142 if (fmtTemplate
[template_pos
] >= '0' &&
143 fmtTemplate
[template_pos
] <= '9')
145 ULONG old_template_pos
= template_pos
;
147 for (arg_pos
= 0; (fmtTemplate
[template_pos
] >= '0' &&
148 fmtTemplate
[template_pos
] <= '9');
152 arg_pos
* 10 + fmtTemplate
[template_pos
] - '0';
155 if (fmtTemplate
[template_pos
] == '$')
159 arg_pos
= arg_counter
;
160 template_pos
= old_template_pos
;
164 arg_pos
= arg_counter
;
169 if (fmtTemplate
[template_pos
] == '-')
176 ** fill character a '0'?
178 if (fmtTemplate
[template_pos
] == '0')
187 if (fmtTemplate
[template_pos
] >= '0' &&
188 fmtTemplate
[template_pos
] <= '9')
190 for (width
= 0; (fmtTemplate
[template_pos
] >= '0' &&
191 fmtTemplate
[template_pos
] <= '9');
195 width
* 10 + fmtTemplate
[template_pos
] - '0';
202 if (fmtTemplate
[template_pos
] == '.')
206 if (fmtTemplate
[template_pos
] >= '0' &&
207 fmtTemplate
[template_pos
] <= '9')
209 for (limit
= 0; (fmtTemplate
[template_pos
] >= '0' &&
210 fmtTemplate
[template_pos
] <= '9');
214 limit
* 10 + fmtTemplate
[template_pos
] -
223 switch (fmtTemplate
[template_pos
])
226 /* IPTR-sized type, can be mixed with %d, %u or %x */
227 datasize
= sizeof(IPTR
);
231 datasize
= sizeof(UQUAD
);
236 if (fmtTemplate
[template_pos
] == 'l')
238 datasize
= sizeof(UQUAD
);
242 datasize
= sizeof(ULONG
);
246 datasize
= sizeof(UWORD
);
251 ** Print it according to the given type info.
253 switch (fmtTemplate
[template_pos
])
255 case 'b': /* BSTR, see autodocs */
257 ** Important parameters:
258 ** arg_pos, left, buflen, limit
261 datasize
= sizeof(IPTR
);
262 BSTR s
= (BSTR
) * (UBYTE
**) ARG(arg_pos
);
264 if (s
!= (BSTR
) BNULL
)
266 buffer
= AROS_BSTR_ADDR(s
);
267 buflen
= AROS_BSTR_strlen(s
);
278 #endif /* !USE_GLOBALLIMIT */
282 case 'd': /* signed decimal */
283 case 'u': /* unsigned decimal */
285 minus
= fmtTemplate
[template_pos
] == 'd';
291 tmp
= *(UQUAD
*) ARG(arg_pos
);
292 //buffer = &buf[16+1];
293 minus
*= (FMTLARGESTTYPE
) tmp
< 0;
298 tmp
= *(ULONG
*) ARG(arg_pos
);
299 //buffer = &buf[8+1];
300 minus
*= (LONG
) tmp
< 0;
306 tmp
= *(UWORD
*) ARG(arg_pos
);
307 //buffer = &buf[4+1];
308 minus
*= (WORD
) tmp
< 0;
314 buffer
= &buf
[BUFFERSIZE
];
317 *--buffer
= (tmp
% 10) + '0';
332 case 'D': /* signed decimal with locale's formatting conventions */
333 case 'U': /* unsigned decimal with locale's formatting conventions */
336 ULONG group_index
= 0;
338 minus
= fmtTemplate
[template_pos
] == 'D';
343 tmp
= *(UQUAD
*) ARG(arg_pos
);
344 minus
*= (FMTLARGESTTYPE
) tmp
< 0;
349 tmp
= *(ULONG
*) ARG(arg_pos
);
350 minus
*= (LONG
) tmp
< 0;
356 tmp
= *(UWORD
*) ARG(arg_pos
);
357 minus
*= (WORD
) tmp
< 0;
363 /* BUFFERSIZE should be big enough to format a string
364 ** according to locale's formatting conventions
366 buffer
= &buf
[BUFFERSIZE
];
369 loc_Grouping
[group_index
] : 255;
373 *--buffer
= (tmp
% 10) + '0';
379 if (groupsize
== 0 && tmp
!= 0)
382 ** Write the separator
386 locale
->loc_GroupSeparator
[group_index
];
389 locale
->loc_Grouping
[group_index
+ 1];
394 ** Supposed to use the previous element
397 locale
->loc_Grouping
[group_index
];
415 case 'p': /* lower case pointer string */
416 case 'P': /* upper case pointer string */
418 width
= sizeof(APTR
) * 2;
419 /* %p is always at least natural pointer size */
420 if (datasize
< sizeof(APTR
))
421 datasize
= sizeof(APTR
);
422 case 'x': /* upper case hexadecimal string */
423 case 'X': /* lower case hexadecimal string */
431 tmp
= *(UQUAD
*) ARG(arg_pos
);
432 //buffer = &buf[16+1];
435 tmp
= *(ULONG
*) ARG(arg_pos
);
436 //buffer = &buf[8+1];
440 tmp
= *(UWORD
*) ARG(arg_pos
);
441 //buffer = &buf[4+1];
445 buffer
= &buf
[BUFFERSIZE
];
447 /* NOTE: x/X is reverse to printf, coz orig RawDoFmt %lx for uppercase. */
448 hexa
= (fmtTemplate
[template_pos
] == 'X' ||
449 fmtTemplate
[template_pos
] ==
450 'p') ? hexarray
: HEXarray
;
453 *--buffer
= hexa
[tmp
& 0x0f];
461 case 's': /* NULL terminated string */
463 datasize
= sizeof(IPTR
);
465 buffer
= *(UBYTE
**) ARG(arg_pos
);
468 * RawDoFmt() in original AmigaOS(tm) formats NULL pointers as empty strings,
469 * and not something like "(null)". Some software may rely on this behavior.
470 * %b is handled in similar manner.
474 buflen
= strlen(buffer
);
479 #endif /* !USE_GLOBALLIMIT */
484 case 'c': /* Character */
490 (UBYTE
) * (UQUAD
*) ARG(arg_pos
);
494 (UBYTE
) * (ULONG
*) ARG(arg_pos
);
499 (UBYTE
) * (WORD
*) ARG(arg_pos
);
508 /* Ignore the faulty '%' */
510 buf
[0] = fmtTemplate
[template_pos
];
513 arg_pos
= --arg_counter
;
522 Now everything I need is known:
523 buffer - contains the string to be printed
524 buflen - size of the string
525 fill - the pad character
526 left - is 1 if the string should be left aligned
527 width - is the minimal width of the field
528 limit - maximum number of characters to output from a string, default ~0
534 #endif /* USE_GLOBALLIMIT */
536 /* Print padding if right aligned */
538 for (i
= buflen
; i
< width
; i
++)
539 AROS_UFC3NR(VOID
, putCharFunc
->h_Entry
,
540 AROS_UFCA(const struct Hook
*, putCharFunc
, A0
),
541 AROS_UFCA(const struct Locale
*, locale
, A2
),
542 AROS_UFCA(UBYTE
, fill
, A1
));
544 /* Print body up to buflen */
545 for (i
= 0; i
< buflen
; i
++)
547 AROS_UFC3NR(VOID
, putCharFunc
->h_Entry
,
548 AROS_UFCA(const struct Hook
*, putCharFunc
, A0
),
549 AROS_UFCA(const struct Locale
*, locale
, A2
),
550 AROS_UFCA(UBYTE
, *buffer
++, A1
));
553 /* Pad right if left aligned */
555 for (i
= buflen
; i
< width
; i
++)
556 AROS_UFC3NR(VOID
, putCharFunc
->h_Entry
,
557 AROS_UFCA(const struct Hook
*, putCharFunc
, A0
),
558 AROS_UFCA(const struct Locale
*, locale
, A2
),
559 AROS_UFCA(UBYTE
, fill
, A1
));
564 if (arg_pos
> max_argpos
)
566 max_argpos
= arg_pos
;
567 max_argpos_datasize
= datasize
;
576 return (APTR
)(ARG(max_argpos
) + max_argpos_datasize
);
579 /*****************************************************************************
582 #include <proto/locale.h>
584 AROS_LH4(APTR
, FormatString
,
587 AROS_LHA(const struct Locale
*, locale
, A0
),
588 AROS_LHA(CONST_STRPTR
, fmtTemplate
, A1
),
589 AROS_LHA(RAWARG
, dataStream
, A2
),
590 AROS_LHA(const struct Hook
*, putCharFunc
, A3
),
593 struct LocaleBase
*, LocaleBase
, 11, Locale
)
611 *****************************************************************************/
616 #if defined(__arm__) || defined(__x86_64__)
617 va_list nullarg
= {};
622 /* Generate the indexes for the provided datastream */
623 GetDataStreamFromFormat(fmtTemplate
, nullarg
, NULL
, NULL
, NULL
, &indexSize
);
624 indices
= alloca(indexSize
);
625 GetDataStreamFromFormat(fmtTemplate
, nullarg
, NULL
, NULL
, indices
, &indexSize
);
627 return InternalFormatString(locale
, fmtTemplate
,
628 dataStream
, indices
, putCharFunc
);