2 Copyright © 1995-2008, The AROS Development Team. All rights reserved.
11 #include <exec/types.h>
12 #include <utility/hooks.h>
13 #include <proto/utility.h>
14 #include <libraries/locale.h>
15 #include <aros/asmcall.h>
16 #include "locale_intern.h"
18 #include <aros/debug.h>
21 typedef QUAD FMTLARGESTTYPE
;
22 typedef UQUAD UFMTLARGESTTYPE
;
23 #else /* USE_QUADFMT */
24 typedef LONG FMTLARGESTTYPE
;
25 typedef ULONG UFMTLARGESTTYPE
;
26 #endif /* USE_QUADFMT */
28 static const UBYTE hexarray
[] = "0123456789abcdef";
29 static const UBYTE HEXarray
[] = "0123456789ABCDEF";
31 /*****************************************************************************
34 #include <proto/locale.h>
36 AROS_LH4(APTR
, FormatString
,
39 AROS_LHA(const struct Locale
*, locale
, A0
),
40 AROS_LHA(CONST_STRPTR
, fmtTemplate
, A1
),
41 AROS_LHA(CONST_APTR
, dataStream
, A2
),
42 AROS_LHA(const struct Hook
*, putCharFunc
, A3
),
45 struct LocaleBase
*, LocaleBase
, 11, Locale
)
63 *****************************************************************************/
78 UWORD indices
[INDICES
];
81 return (APTR
)dataStream
;
83 template_pos
= 0; /* Current position in the template string */
84 state
= OUTPUT
; /* current state of parsing */
88 stream
= (ULONG
*) dataStream
;
89 scanning
= TRUE
; /* The first time I will go through
90 and determine the width of the data in the dataStream */
93 memclr(indices
, sizeof(indices
));
95 memset(indices
, 0, sizeof(indices
));
101 ** A format description starts here?
103 if (fmtTemplate
[template_pos
] == '%')
106 state
= FOUND_FORMAT
;
113 ** Call the hook for this character
117 AROS_UFC3(VOID
, putCharFunc
->h_Entry
,
118 AROS_UFCA(const struct Hook
*, putCharFunc
, A0
),
119 AROS_UFCA(const struct Locale
*, locale
, A2
),
120 AROS_UFCA(UBYTE
, fmtTemplate
[template_pos
], A1
));
124 ** End of template string? -> End of this function.
126 if (fmtTemplate
[template_pos
] == '\0')
131 ** The scanning phase is over. Next time we do the output.
138 ** prepare the indices array
145 while (i
<= max_argpos
)
149 _sum
= sum
+ indices
[i
];
161 ** We already went through the output phase. So this is
170 //kprintf("OUTPUT: template_pos: %d\n",template_pos);
176 ** The '%' was found in the template string
180 //kprintf("FOUND_FORMAT: template_pos: %d\n",template_pos);
182 ** Does the user want the '%' to be printed?
184 if (fmtTemplate
[template_pos
] == '%')
188 AROS_UFC3(VOID
, putCharFunc
->h_Entry
,
189 AROS_UFCA(const struct Hook
* , putCharFunc
, A0
),
190 AROS_UFCA(const struct Locale
*, locale
, A2
),
191 AROS_UFCA(UBYTE
, fmtTemplate
[template_pos
], A1
));
194 arg_counter
--; //stegerg
200 ** Template format: %[arg_pos$][flags][width][.limit][length]type
202 ** arg_pos specifies the position of the argument in the dataStream
203 ** flags only '-' is allowd
206 ** datasize size of the datatype
207 ** type b,d,D,u,U,x,X,s,c
210 BOOL left
= FALSE
; // no flag was found
217 UFMTLARGESTTYPE tmp
= 0;
218 #define BUFFERSIZE 128
219 UBYTE buf
[BUFFERSIZE
];
226 //kprintf("next char: %c\n",fmtTemplate[template_pos]);
228 if (fmtTemplate
[template_pos
] >= '0' &&
229 fmtTemplate
[template_pos
] <= '9')
231 ULONG old_template_pos
= template_pos
;
233 for (arg_pos
= 0; (fmtTemplate
[template_pos
] >= '0' &&
234 fmtTemplate
[template_pos
] <= '9'); template_pos
++)
236 arg_pos
= arg_pos
* 10 + fmtTemplate
[template_pos
] - '0';
239 if (fmtTemplate
[template_pos
] == '$')
243 arg_pos
= arg_counter
;
244 template_pos
= old_template_pos
;
248 arg_pos
= arg_counter
;
253 if (fmtTemplate
[template_pos
] == '-')
260 ** fill character a '0'?
262 if (fmtTemplate
[template_pos
] == '0')
271 if (fmtTemplate
[template_pos
] >= '0' &&
272 fmtTemplate
[template_pos
] <= '9')
274 for (width
= 0; (fmtTemplate
[template_pos
] >= '0' &&
275 fmtTemplate
[template_pos
] <= '9'); template_pos
++)
277 width
= width
* 10 + fmtTemplate
[template_pos
] - '0';
284 if (fmtTemplate
[template_pos
] == '.')
288 if (fmtTemplate
[template_pos
] >= '0' &&
289 fmtTemplate
[template_pos
] <= '9')
291 for (limit
= 0; (fmtTemplate
[template_pos
] >= '0' &&
292 fmtTemplate
[template_pos
] <= '9'); template_pos
++)
294 limit
= limit
* 10 + fmtTemplate
[template_pos
] - '0';
302 switch (fmtTemplate
[template_pos
])
309 #endif /* USE_QUADFMT */
314 if (fmtTemplate
[template_pos
] == 'l')
320 #endif /* USE_QUADFMT */
330 ** Print it according to the given type info.
332 switch (fmtTemplate
[template_pos
])
334 case 'b': /* BSTR, see autodocs */
336 ** Important parameters:
337 ** arg_pos, left, buflen, limit
341 BSTR s
= (BSTR
)*(UBYTE
**)(((IPTR
)stream
)+indices
[arg_pos
-1]);
343 buffer
= AROS_BSTR_ADDR(s
);
344 buflen
= AROS_BSTR_strlen(s
);
349 #endif /* !USE_GLOBALLIMIT */
352 indices
[arg_pos
-1] = sizeof(BPTR
);
355 case 'd': /* signed decimal */
356 case 'u': /* unsigned decimal */
358 minus
= fmtTemplate
[template_pos
] == 'd';
366 tmp
= *(UQUAD
*)(((IPTR
)stream
)+indices
[arg_pos
-1]);
367 //buffer = &buf[16+1];
368 minus
*= (FMTLARGESTTYPE
) tmp
< 0;
372 #endif /* USE_QUADFMT */
375 tmp
= *(ULONG
*)(((IPTR
)stream
)+indices
[arg_pos
-1]);
376 //buffer = &buf[8+1];
377 minus
*= (LONG
) tmp
< 0;
383 tmp
= *(UWORD
*)(((IPTR
)stream
)+indices
[arg_pos
-1]);
384 //buffer = &buf[4+1];
385 minus
*= (WORD
) tmp
< 0;
391 buffer
= &buf
[BUFFERSIZE
];
394 *--buffer
= (tmp
% 10) + '0';
408 indices
[arg_pos
-1] = datasize
;
411 case 'D': /* signed decimal with locale's formatting conventions */
412 case 'U': /* unsigned decimal with locale's formatting conventions */
416 ULONG group_index
= 0;
418 minus
= fmtTemplate
[template_pos
] == 'D';
424 tmp
= *(UQUAD
*)(((IPTR
)stream
)+indices
[arg_pos
-1]);
425 minus
*= (FMTLARGESTTYPE
) tmp
< 0;
429 #endif /* USE_QUADFMT */
432 tmp
= *(ULONG
*)(((IPTR
)stream
)+indices
[arg_pos
-1]);
433 minus
*= (LONG
) tmp
< 0;
439 tmp
= *(UWORD
*)(((IPTR
)stream
)+indices
[arg_pos
-1]);
440 minus
*= (WORD
) tmp
< 0;
446 /* BUFFERSIZE should be big enough to format a string
447 ** according to locale's formatting conventions
449 buffer
= &buf
[BUFFERSIZE
];
450 groupsize
= locale
? locale
->loc_Grouping
[group_index
] : 255;
454 *--buffer
= (tmp
% 10) + '0';
460 if (groupsize
== 0 && tmp
!= 0)
463 ** Write the separator
466 *--buffer
= locale
->loc_GroupSeparator
[group_index
];
468 groupsize
= locale
->loc_Grouping
[group_index
+1];
473 ** Supposed to use the previous element
475 groupsize
= locale
->loc_Grouping
[group_index
];
492 indices
[arg_pos
-1] = datasize
;
495 case 'x': /* upper case hexadecimal string */
496 case 'X': /* lower case hexadecimal string */
497 case 'p': /* lower case pointer string */
498 case 'P': /* upper case pointer string */
504 /* %p is always at least natural pointer size (32bit) */
505 if (datasize
< sizeof(void *) && (fmtTemplate
[template_pos
] == 'p' ||
506 fmtTemplate
[template_pos
] == 'P'))
508 datasize
= sizeof(void *);
515 tmp
= *(UQUAD
*)(((IPTR
)stream
)+indices
[arg_pos
-1]);
516 //buffer = &buf[16+1];
518 #endif /* USE_QUADFMT */
521 tmp
= *(ULONG
*)(((IPTR
)stream
)+indices
[arg_pos
-1]);
522 //buffer = &buf[8+1];
526 tmp
= *(UWORD
*)(((IPTR
)stream
)+indices
[arg_pos
-1]);
527 //buffer = &buf[4+1];
531 buffer
= &buf
[BUFFERSIZE
];
533 /* NOTE: x/X is reverse to printf, coz orig RawDoFmt %lx for uppercase. */
534 hexa
= (fmtTemplate
[template_pos
] == 'X' ||
535 fmtTemplate
[template_pos
] == 'p') ? hexarray
: HEXarray
;
538 *--buffer
= hexa
[tmp
&0x0f];
545 indices
[arg_pos
-1] = datasize
;
548 case 's': /* NULL terminated string */
552 buffer
= *(UBYTE
**)(((IPTR
)stream
)+indices
[arg_pos
-1]);
559 buflen
= strlen(buffer
);
564 #endif /* !USE_GLOBALLIMIT */
567 indices
[arg_pos
-1] = sizeof(UBYTE
*); /* the pointer has 4 bytes */
571 case 'c': /* Character */
578 buf
[0] = (UBYTE
)*(UQUAD
*)(((IPTR
)stream
)+indices
[arg_pos
-1]);
580 #endif /* USE_QUADFMT */
583 buf
[0] = (UBYTE
)*(ULONG
*)(((IPTR
)stream
)+indices
[arg_pos
-1]);
587 buf
[0] = (UBYTE
)*(WORD
*)(((IPTR
)stream
)+indices
[arg_pos
-1]);
594 indices
[arg_pos
-1] = datasize
;
598 /* Ignore the faulty '%' */
602 buf
[0] = fmtTemplate
[template_pos
];
607 arg_pos
= --arg_counter
;
617 Now everything I need is known:
618 buffer - contains the string to be printed
619 buflen - size of the string
620 fill - the pad character
621 left - is 1 if the string should be left aligned
622 width - is the minimal width of the field
623 limit - maximum number of characters to output from a string, default ~0
629 #endif /* USE_GLOBALLIMIT */
631 /* Print padding if right aligned */
633 for (i
= buflen
; i
< width
; i
++)
634 AROS_UFC3(VOID
, putCharFunc
->h_Entry
,
635 AROS_UFCA(const struct Hook
*, putCharFunc
, A0
),
636 AROS_UFCA(const struct Locale
*, locale
, A2
),
637 AROS_UFCA(UBYTE
, fill
, A1
)
640 /* Print body up to buflen */
641 for (i
= 0; i
< buflen
; i
++)
643 AROS_UFC3(VOID
, putCharFunc
->h_Entry
,
644 AROS_UFCA(const struct Hook
*, putCharFunc
, A0
),
645 AROS_UFCA(const struct Locale
*, locale
, A2
),
646 AROS_UFCA(UBYTE
, *buffer
++ , A1
)
650 /* Pad right if left aligned */
652 for (i
= buflen
; i
< width
; i
++)
653 AROS_UFC3(VOID
, putCharFunc
->h_Entry
,
654 AROS_UFCA(const struct Hook
*, putCharFunc
, A0
),
655 AROS_UFCA(const struct Locale
*, locale
, A2
),
656 AROS_UFCA(UBYTE
, fill
, A1
)
662 if (arg_pos
> max_argpos
)
663 max_argpos
= arg_pos
;
671 return (APTR
) (((IPTR
)stream
) + indices
[max_argpos
]);