2 Copyright © 1995-2007, 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(struct Locale
*, locale
, A0
),
40 AROS_LHA(STRPTR
, fmtTemplate
, A1
),
41 AROS_LHA(APTR
, dataStream
, A2
),
42 AROS_LHA(struct Hook
*, putCharFunc
, A3
),
45 struct LocaleBase
*, LocaleBase
, 11, Locale
)
64 27-11-96 digulla automatically created from
65 locale_lib.fd and clib/locale_protos.h
67 *****************************************************************************/
82 UWORD indices
[INDICES
];
87 template_pos
= 0; /* Current position in the template string */
88 state
= OUTPUT
; /* current state of parsing */
92 stream
= (ULONG
*) dataStream
;
93 scanning
= TRUE
; /* The first time I will go through
94 and determine the width of the data in the dataStream */
97 memclr(indices
, sizeof(indices
));
99 memset(indices
, 0, sizeof(indices
));
105 ** A format description starts here?
107 if (fmtTemplate
[template_pos
] == '%')
110 state
= FOUND_FORMAT
;
117 ** Call the hook for this character
121 AROS_UFC3(VOID
, putCharFunc
->h_Entry
,
122 AROS_UFCA(struct Hook
*, putCharFunc
, A0
),
123 AROS_UFCA(struct Locale
*, locale
, A2
),
124 AROS_UFCA(UBYTE
, fmtTemplate
[template_pos
], A1
));
128 ** End of template string? -> End of this function.
130 if (fmtTemplate
[template_pos
] == '\0')
135 ** The scanning phase is over. Next time we do the output.
142 ** prepare the indices array
149 while (i
<= max_argpos
)
153 _sum
= sum
+ indices
[i
];
165 ** We already went through the output phase. So this is
174 //kprintf("OUTPUT: template_pos: %d\n",template_pos);
180 ** The '%' was found in the template string
184 //kprintf("FOUND_FORMAT: template_pos: %d\n",template_pos);
186 ** Does the user want the '%' to be printed?
188 if (fmtTemplate
[template_pos
] == '%')
192 AROS_UFC3(VOID
, putCharFunc
->h_Entry
,
193 AROS_UFCA(struct Hook
* , putCharFunc
, A0
),
194 AROS_UFCA(struct Locale
*, locale
, A2
),
195 AROS_UFCA(UBYTE
, fmtTemplate
[template_pos
], A1
));
198 arg_counter
--; //stegerg
204 ** Template format: %[arg_pos$][flags][width][.limit][length]type
206 ** arg_pos specifies the position of the argument in the dataStream
207 ** flags only '-' is allowd
210 ** datasize size of the datatype
211 ** type b,d,D,u,U,x,X,s,c
214 BOOL left
= FALSE
; // no flag was found
221 UFMTLARGESTTYPE tmp
= 0;
222 #define BUFFERSIZE 128
223 UBYTE buf
[BUFFERSIZE
];
230 //kprintf("next char: %c\n",fmtTemplate[template_pos]);
232 if (fmtTemplate
[template_pos
] >= '0' &&
233 fmtTemplate
[template_pos
] <= '9')
235 ULONG old_template_pos
= template_pos
;
237 for (arg_pos
= 0; (fmtTemplate
[template_pos
] >= '0' &&
238 fmtTemplate
[template_pos
] <= '9'); template_pos
++)
240 arg_pos
= arg_pos
* 10 + fmtTemplate
[template_pos
] - '0';
243 if (fmtTemplate
[template_pos
] == '$')
247 arg_pos
= arg_counter
;
248 template_pos
= old_template_pos
;
252 arg_pos
= arg_counter
;
257 if (fmtTemplate
[template_pos
] == '-')
264 ** fill character a '0'?
266 if (fmtTemplate
[template_pos
] == '0')
275 if (fmtTemplate
[template_pos
] >= '0' &&
276 fmtTemplate
[template_pos
] <= '9')
278 for (width
= 0; (fmtTemplate
[template_pos
] >= '0' &&
279 fmtTemplate
[template_pos
] <= '9'); template_pos
++)
281 width
= width
* 10 + fmtTemplate
[template_pos
] - '0';
288 if (fmtTemplate
[template_pos
] == '.')
292 if (fmtTemplate
[template_pos
] >= '0' &&
293 fmtTemplate
[template_pos
] <= '9')
295 for (limit
= 0; (fmtTemplate
[template_pos
] >= '0' &&
296 fmtTemplate
[template_pos
] <= '9'); template_pos
++)
298 limit
= limit
* 10 + fmtTemplate
[template_pos
] - '0';
306 switch (fmtTemplate
[template_pos
])
313 #endif /* USE_QUADFMT */
318 if (fmtTemplate
[template_pos
] == 'l')
324 #endif /* USE_QUADFMT */
334 ** Print it according to the given type info.
336 switch (fmtTemplate
[template_pos
])
338 case 'b': /* BSTR, see autodocs */
340 ** Important parameters:
341 ** arg_pos, left, buflen, limit
345 BSTR s
= (BSTR
)*(UBYTE
**)(((IPTR
)stream
)+indices
[arg_pos
-1]);
347 buffer
= AROS_BSTR_ADDR(s
);
348 buflen
= AROS_BSTR_strlen(s
);
353 #endif /* !USE_GLOBALLIMIT */
356 indices
[arg_pos
-1] = sizeof(BPTR
);
359 case 'd': /* signed decimal */
360 case 'u': /* unsigned decimal */
362 minus
= fmtTemplate
[template_pos
] == 'd';
370 tmp
= *(UQUAD
*)(((IPTR
)stream
)+indices
[arg_pos
-1]);
371 //buffer = &buf[16+1];
372 minus
*= (FMTLARGESTTYPE
) tmp
< 0;
376 #endif /* USE_QUADFMT */
379 tmp
= *(ULONG
*)(((IPTR
)stream
)+indices
[arg_pos
-1]);
380 //buffer = &buf[8+1];
381 minus
*= (LONG
) tmp
< 0;
387 tmp
= *(UWORD
*)(((IPTR
)stream
)+indices
[arg_pos
-1]);
388 //buffer = &buf[4+1];
389 minus
*= (WORD
) tmp
< 0;
395 buffer
= &buf
[BUFFERSIZE
];
398 *--buffer
= (tmp
% 10) + '0';
412 indices
[arg_pos
-1] = datasize
;
415 case 'D': /* signed decimal with locale's formatting conventions */
416 case 'U': /* unsigned decimal with locale's formatting conventions */
420 ULONG group_index
= 0;
422 minus
= fmtTemplate
[template_pos
] == 'D';
428 tmp
= *(UQUAD
*)(((IPTR
)stream
)+indices
[arg_pos
-1]);
429 minus
*= (FMTLARGESTTYPE
) tmp
< 0;
433 #endif /* USE_QUADFMT */
436 tmp
= *(ULONG
*)(((IPTR
)stream
)+indices
[arg_pos
-1]);
437 minus
*= (LONG
) tmp
< 0;
443 tmp
= *(UWORD
*)(((IPTR
)stream
)+indices
[arg_pos
-1]);
444 minus
*= (WORD
) tmp
< 0;
450 /* BUFFERSIZE should be big enough to format a string
451 ** according to locale's formatting conventions
453 buffer
= &buf
[BUFFERSIZE
];
454 groupsize
= locale
? locale
->loc_Grouping
[group_index
] : 255;
458 *--buffer
= (tmp
% 10) + '0';
464 if (groupsize
== 0 && tmp
!= 0)
467 ** Write the separator
470 *--buffer
= locale
->loc_GroupSeparator
[group_index
];
472 groupsize
= locale
->loc_Grouping
[group_index
+1];
477 ** Supposed to use the previous element
479 groupsize
= locale
->loc_Grouping
[group_index
];
496 indices
[arg_pos
-1] = datasize
;
499 case 'x': /* upper case hexadecimal string */
500 case 'X': /* lower case hexadecimal string */
501 case 'p': /* lower case pointer string */
502 case 'P': /* upper case pointer string */
508 /* %p is always at least natural pointer size (32bit) */
509 if (datasize
< sizeof(void *) && (fmtTemplate
[template_pos
] == 'p' ||
510 fmtTemplate
[template_pos
] == 'P'))
512 datasize
= sizeof(void *);
519 tmp
= *(UQUAD
*)(((IPTR
)stream
)+indices
[arg_pos
-1]);
520 //buffer = &buf[16+1];
522 #endif /* USE_QUADFMT */
525 tmp
= *(ULONG
*)(((IPTR
)stream
)+indices
[arg_pos
-1]);
526 //buffer = &buf[8+1];
530 tmp
= *(UWORD
*)(((IPTR
)stream
)+indices
[arg_pos
-1]);
531 //buffer = &buf[4+1];
535 buffer
= &buf
[BUFFERSIZE
];
537 /* NOTE: x/X is reverse to printf, coz orig RawDoFmt %lx for uppercase. */
538 hexa
= (fmtTemplate
[template_pos
] == 'X' ||
539 fmtTemplate
[template_pos
] == 'p') ? hexarray
: HEXarray
;
542 *--buffer
= hexa
[tmp
&0x0f];
549 indices
[arg_pos
-1] = datasize
;
552 case 's': /* NULL terminated string */
556 buffer
= *(UBYTE
**)(((IPTR
)stream
)+indices
[arg_pos
-1]);
563 buflen
= strlen(buffer
);
568 #endif /* !USE_GLOBALLIMIT */
571 indices
[arg_pos
-1] = sizeof(UBYTE
*); /* the pointer has 4 bytes */
575 case 'c': /* Character */
582 buf
[0] = (UBYTE
)*(UQUAD
*)(((IPTR
)stream
)+indices
[arg_pos
-1]);
584 #endif /* USE_QUADFMT */
587 buf
[0] = (UBYTE
)*(ULONG
*)(((IPTR
)stream
)+indices
[arg_pos
-1]);
591 buf
[0] = (UBYTE
)*(WORD
*)(((IPTR
)stream
)+indices
[arg_pos
-1]);
598 indices
[arg_pos
-1] = datasize
;
602 /* Ignore the faulty '%' */
606 buf
[0] = fmtTemplate
[template_pos
];
611 arg_pos
= --arg_counter
;
621 Now everything I need is known:
622 buffer - contains the string to be printed
623 buflen - size of the string
624 fill - the pad character
625 left - is 1 if the string should be left aligned
626 width - is the minimal width of the field
627 limit - maximum number of characters to output from a string, default ~0
633 #endif /* USE_GLOBALLIMIT */
635 /* Print padding if right aligned */
637 for (i
= buflen
; i
< width
; i
++)
638 AROS_UFC3(VOID
, putCharFunc
->h_Entry
,
639 AROS_UFCA(struct Hook
*, putCharFunc
, A0
),
640 AROS_UFCA(struct Locale
*, locale
, A2
),
641 AROS_UFCA(UBYTE
, fill
, A1
)
644 /* Print body up to buflen */
645 for (i
= 0; i
< buflen
; i
++)
647 AROS_UFC3(VOID
, putCharFunc
->h_Entry
,
648 AROS_UFCA(struct Hook
*, putCharFunc
, A0
),
649 AROS_UFCA(struct Locale
*, locale
, A2
),
650 AROS_UFCA(UBYTE
, *buffer
++ , A1
)
654 /* Pad right if left aligned */
656 for (i
= buflen
; i
< width
; i
++)
657 AROS_UFC3(VOID
, putCharFunc
->h_Entry
,
658 AROS_UFCA(struct Hook
*, putCharFunc
, A0
),
659 AROS_UFCA(struct Locale
*, locale
, A2
),
660 AROS_UFCA(UBYTE
, fill
, A1
)
666 if (arg_pos
> max_argpos
)
667 max_argpos
= arg_pos
;
675 return (APTR
) (((IPTR
)stream
) + indices
[max_argpos
]);